php-interceptors-and-delegation

“Intercept” and “Delegate” in PHP

PHP provides built-in interceptor methods, which can intercept messages sent to undefined methods and properties (a kind of overloading).

The interceptor methods:

Method Description
__get( $property ) Invoked when an undefined property is accessed
__set( $property, $value ) Invoked when a value is assigned to an undefined property
__isset( $property ) Invoked when isset() is called on an undefined property
__unset( $property ) Invoked when unset() is called on an undefined property
__call( $method, $arg_array ) Invoked when an undefined method is called

The __get() and __set() methods are designed for working with properties that have not been declared in a class (or its parents).
__get() is invoked when client code attempts to read an undeclared property. It is called automatically with a single string argument containing the name of the property that the client is attempting to access. Whatever you return from the __get() method will be sent back to the client as if the target property exists with that value.

Here’s a quick example:

class Person {
	function __get($property) {
		$method = "get{$property}";
		if (method_exists ( $this, $method )) {
			return $this->$method ();
		}
	}
	function getName() {
		return "Valisu";
	}
	function getAge() {
		return 26;
	}
}
$p = new Person ();
print $p->name;

Here the __get() function takes the property name and construct a new string, prepending the word “get”.
This string is passed to a function called method_exists(), which accepts an object and a method name and tests for method existence. If the method does exist, it is invoked and its return value is passed to the client. So if the client requests a $name property the getName() method is invoked behind the scenes and returns the ‘Valisu’ string.
If the method does not exist, nothing happens and the name property will resolve to NULL.

The __isset() method works in a similar way to __get(). For instance:

function __isset($property) {
	$method = "get{$property}";
	return (method_exists ( $this, $method ));
}
............
if (isset ( $p->name )) {
	print $p->name;
}

The __set() method is invoked when client code attempts to assign to an undefined property. It is passed two arguments: the name of the property, and the value the client is attempting to set. You can then decide how to work with these arguments.

class Person {
	private $_name;
	private $_age;
	function __set($property, $value) {
		$method = "set{$property}";
		if (method_exists ( $this, $method )) {
			return $this->$method ( $value );
		}
	}
	function setName($name) {
		$this->_name = $name;
		if (! is_null ( $name )) {
			$this->_name = strtoupper ( $this->_name );
		}
	}
	function setAge($age) {
		$this->_age = strtoupper ( $age );
	}
}
$p = new Person ();
$p->name = "LoL";
// the $_name property becomes 'LoL'

As you might expect, __unset() mirrors __set().
The __call() method can be used for delegation.

Delegation

Is the mechanism by which one object passes method invocations on to a second. It is similar to inheritance, in that a child class passes on a method call to its parent implementation.

class Person {
	private $writer;

        /** 
	 * Use PersonWriter object as a constructor argument
	 * and stores it in a property variable
	 * @param object $writer
	 */
	function __construct(PersonWriter $writer) {
		$this->writer = $writer;
	}
	
        /**
	 * Testing for a method of the same name as in $methodname, 
         * in the PersonWriter object
	 * If I encounter such a method, I delegate the method call 
         * to the PersonWriter object, passing my current instance to
         * it (in the $this pseudo-variable)
	 * @param string $methodname
	 * @param array $args holds all arguments passed by the client
	 */
	function __construct(PersonWriter $writer) {
		$this->writer = $writer;
	}
	function __call($methodname, $args) {
		if (method_exists ( $this->writer, $methodname )) {
			return $this->writer->$methodname ( $this );
		}
	}
	function getName() {
		return "koko";
	}
	function getAge() {
		return 20;
	}
}

class PersonWriter {
	function writeName(Person $p) {
		print $p->getName () . "\n";
	}
	function writeAge(Person $p) {
		print $p->getAge () . "\n";
	}
}

$person = new Person( new PersonWriter() );
$person->writeName();
// displays 'koko'
email-newsletter

Dev'Letter

Professional opinion about Web Development Techniques, Tools & Productivity.
Only once a month!

Any suggestion on what to write next time ? Submit now

Opinions

avatar
550
  Subscribe  
Notify of

Related Posts