Magic __call() vs. multiple setters

I recently came across a situation where a few of my setProperty() methods where exactly the same. Since I’ve gotten into improving my coding, this bugged me because it was repetitious code.
Example:

public function setFoo($foo=null) {
	if (is_string($foo)||is_numeric($foo)) {
		$this->foo=$foo;
		return $this;
	}
	throw new Custom_Example_Exception("Please provide a proper string or numeric",Custom_Example_Exception::INVALID_TYPE);
}

public function setBar($bar=null) {
	if (is_string($bar)||is_numeric($bar)) {
		$this->bar=$bar;
		return $this;
	}
	throw new Custom_Example_Exception("Please provide a proper string or numeric",Custom_Example_Exception::INVALID_TYPE);
}

Notice a pattern there? Me too. If all my setters were like this, I could do

public function setProperty($property=null) {
	if (is_string($property)||is_numeric($property)) {
		$this->{$property}=$property;
		return $this;
	}
	throw new Custom_Example_Exception("Please provide a proper string or numeric",Custom_Example_Exception::INVALID_TYPE);
}

with appropriate traps in the __call() and maybe even __set() methods.

However, my situation is that not all the setters for my class follow this pattern so that solution means that I have to make __call() look for specific setters.

public function __call($method,$args) {
	$trapThese=array("Foo","Bar","Baz");
	preg_match('/set(*.?)/im',$method,$matches);
	if (!empty($matches)&&in_array($matches[1],$trapThese)) {
		if(is_string($args[0])||is_numeric($args[0])) {
		$propertyName=strtolower($matches[1]);
			$this->{$propertyName}=$args[0];
		}
		throw new Custom_Example_Exception("Please provide a proper string or numeric.\nException trapped in call to $method",Custom_Example_Exception::INVALID_TYPE);
	} else {
		$this->{$method}($args);
	}
}

And I’m pretty sure that this code snippet ($this->{$method}($args);) is the Wrong Way of Doing It. So I’ll just have to settle for the redundant setFoo(),setBar,etc even though a part of me knows that there has to be a Better Way. Or maybe there is just No Way of Doing It Well.

I think it is probably only a matter of preference but in terms of testability, elegance, maintainability, whatever…what do you prefer, doing a magic __call() or making setFoo(),setBar(),setBaz,etc.

string searching, you’re doing it wrong

First off, I’m not trying to be a complete jack-ass, just a helpful one. This article, by Stefan Ashwell, popped up on my news feed and I wanted to comment on it but can’t remember my login for the site and after 10 minutes of waiting the password reset email has yet to arrive. The non-arrival of the password process is irritating me and shows in this article title and my tone.

In the article, Stefan shows how strpos or stripos to locate a desired string or block of text.

The example he gives is as follows:

if ( stripos($sentence, 'string') ) {
   // yes it does
} else {
   // no it doesn't
} 

The problem with this example is that it will yield a false positive. This is a common mistake made by a lot of people. If we examine the php manual entry further we see, “Returns the numeric position of the first occurrence of needle in the haystack string.” The key word being numeric. This means if the string position is 0, then the expression ( stripos($sentence, 'string') ) will evaluate to false.

EDIT: Expanded explaination on why this can yield a false positive. If the string your searching for is at the beginning of the sentence, then the position returned is 0. When php reaches the statement if ( stripos($sentence, 'string') ) it interprets the return value (0) as false.

Here is a more expanded example:


$eval=(stripos('The quick brown fox jumped over the lazy dog','The'));

echo '($eval) : ';
echo ($eval) ? "pass\n" : "fail whale\n";
echo '($eval==0) : ';
echo ($eval==0) ? "pass\n" : "fail whale\n";
echo '($eval===false)';
echo ($eval===false) ? "pass\n" : "fail whale\n";
echo 'eval is '.$eval."\n";

/**
output is:

($eval) : fail whale
($eval==0) : pass
($eval===false)fail whale
eval is 0

*/

As you can see, if you want to properly search for a string using stripos or strpos, you must test for the boolean value of false ($eval===false). Alternately, you can use regex, if you’re comfortable with it. I’m of the opinion that learning some basic regex doesn’t ever hurt you.

I want to re-iterate that I wanted to leave this whole post as a comment but that doesn’t seem possible right now since that email has yet to arrive and the article requires login for commenting.