php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Request #53138 __instanceof magic method
Submitted: 2010-10-22 13:00 UTC Modified: 2010-10-22 15:17 UTC
From: tom at r dot je Assigned:
Status: Not a bug Package: *General Issues
PHP Version: 5.3.3 OS: N/A
Private report: No CVE-ID: None
 [2010-10-22 13:00 UTC] tom at r dot je
Description:
------------
as it stands, it's possible to create a wrapper e.g.


<?php
class A {
	
}

class AWrapper {
	protected $a;
	
	public function __construct(A $a) {
		$this->a = $a;
	}
	
	public function __set($name, $value) {
		$this->a->$name = $value;
	}
	
	public function __get($name) {
		return $this->a->$name;
	}
	
	public function __call($func, $args) {
		return call_user_func_array(array($this->a, $func), $args);
	}
}
?>

AWrapper, now mimics the interface of A. It will work as a substitute for A, anywhere A is required.

The problem is, type checking. Anywhere class "A" is used, it may be type hinted or checked using instanceof

e.g.

function setA(A $a) {

}

or $foo isntanceof 'A';

If an __instanceof magic method existed, it would  be possible to get around this and have true wrapper classes.

For example: 

public function __instanceof() {
	return 'A';
}

Or perhaps it should return an array to allow it to wrap multiple classes.



Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2010-10-22 15:17 UTC] cataphract@php.net
-Status: Open +Status: Bogus
 [2010-10-22 15:17 UTC] cataphract@php.net
Make A an interface and have AWrapper implement or extend A.

Overloading the instanceof operator is not an acceptable solution.
 [2010-10-26 16:00 UTC] tom at r dot je
Why is that?

While that solution works, it's clunky. 

For example for debugging/logging I may want to do something prior to each 
method call:

class Wrapper {
	protected $object;
	
	private function log($details) {

	}

	public function __construct($object) {
		$this->object = $object;
	}
	
	public function __set($name, $value) {
		$this->object->$name = $value;
	}
	
	public function __get($name) {
		return $this->object->$name;
	}
	
	public function __call($func, $args) {
		$this->log('Called ' . $func);
		return call_user_func_array(array($this->object, $func), $args);
	}
}
?>

Essentially the adapter pattern for any object. This works until you pass it 
around. 

Extending the A wont work because:

__call will never get called because the methods exist


Also, this wrapper class could wrap *any* class in the system. Extending every 
class isn't viable.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Sun May 19 02:01:35 2024 UTC