constraining php dynamic properties

February 18, 2010

in software, web

PHP supports dynamic properties. Generally, I don’t find this feature to be very helpful at all, as it makes your code prone to bugs caused by property misspellings (yet another reason I’m not a huge fan of PHP at all). Take this snippet:

1
2
3
4
5
6
7
8
9
10
class foo {
	public $thing = "hi\n";
}
 
$bar = new foo;
echo $bar->thing;
echo $bar->thing2;
 
$bar->ThisPropertyDoesNotExist = "Wow\n";
echo $bar->ThisPropertyDoesNotExist;

the output will look like this:

hi
Wow

Line 6 works as expected — it accesses a property defined on the object. However, let’s say line 7 was just a misspelling — you actually intended to get the value of $thing, not $thing2. There’s no error, and you just get ‘null’. What happens when you need to check $thing for null in your code and you mistyped? Bugs. Bugs are what happen. Lines 9-10 illustrate the inverse of this problem — you can just set a random, non-existant property, then later retrieve it.

I like it when code is a little tighter, so I whipped together a quick (albeit very simple) base class that will constrain properties on a PHP object. You inherit from it, and in the constructor define the allowable properties, and can even set an initial value:

class ConstrainProperties {
	private $data = array();
 
	protected function __construct($props) {
		$this->data = $props;
	}
 
	protected function check_prop($name) {
		if (!array_key_exists($name, $this->data)) {
			$message = "Property does not exist: [" . $name . "]\n";
			$message .= "Existing Properties:";
			foreach($this->data as $k => $v) {
				$message .= "\n" . $k;
			}
			throw new Exception($message);
		}
		return true;
	}
 
	public function __set($name, $value) {
		if ($this->check_prop($name)) {
			$this->data[$name] = $value;
		}
	}
 
	public function __get($name) {
		if ($this->check_prop($name)) {
				return $this->data[$name];
		}
	}
 
	public function __isset($name) {
		return isset($this->data[$name]);
	}
 
	public function __unset($name) {
		unset($this->data[$name]);
	}
}

So, as an example, I rewrite our original “foo” class as this:

class foo extends ConstrainProperties {
	function __construct() {
		parent::__construct(array("thing" => "hi\n"));
	}
}

Now attempting to access the “thing2″ property gets you an error:

PHP Fatal error:  Uncaught exception 'Exception' with message 'Property does not exist: [thing2]
Existing Properties:
thing'

… and that should keep you from making spelling mistakes.

cheers

Leave a Comment

Previous post:

Next post: