Since you can no longer assign to $this in PHP5, how would one call a
method defined in a particular ancestor class that has been overridden
by the current class or a more recent ancestor? In PHP4 doing this was
hackish, but worked.
For example:
class A {
function foo() {
echo "A::foo";
// Do stuff with $this (not a static method)
}
}
class B extends A {
function foo() {
echo "B::foo";
}
}
class C extends B {
function bar() {
// Inside C, i should be able to do the following since $this is an
instance of A:
A::foo();
}
}
class D {
function bar() {
$c = new C;
// I'd like to call the A::foo method of C here...
// In PHP4, I could do something like:
$othis = &$this;
$this = &$c;
A::foo();
$this = &$othis;
}
}
How would one emulate the same sort of functionality as in D::bar with
PHP5? The best I've been able to figure out is to build the appropriate
code in a method and eval it: (add the following method to class A)
function call_user_method_array($method, $args = null) {
if (is_array($method))
$method = $method[0] .'::'. $method[1];
else
$method = '$this->'. $method;
$code = 'return '. $method .'(';
if (isset($args)) {
$n = count($args);
if ($n >= 1) {
$code .= '$args[0]';
for ($i = 1; $i < $n; ++$i) {
$code .= ',$args['.$i.']';
}
}
}
$code .= ');';
return eval($code);
}
Then D::bar would be more like:
function bar() {
$c = new C;
$c->call_user_method_array("A::foo");
}
I'd assume this has big performance penalties compared to the old PHP4
way. It would be nice if call_user_func/call_user_func_array could be
used instead of an eval, but doing so results in $this not being set in
the called method. For example, the following does not work as I'd
expect it to when $method is given as Array(ancestor_class_name,
method_name) since it seems to treat it as a static method call ($this
is not set within the called method):
function call_user_method_array($method, $args = null) {
if (!is_array($method))
$method = Array(&$this, $method);
return call_user_func_array($method, $args);
}
Also, it is not possible to do something like the following because PHP5
dies on the assignment to $this during parsing, and not execution:
function call_user_method_array($method, $args = null) {
if (preg_match('/^4/', PHP_VERSION)) {
$othis = &$this;
$this = &$c;
A::foo();
$this = &$othis;
} else {
... PHP 5 code with eval here ...
}
}
The only way to make the above example work is to eval the PHP4 version
(or perhaps include it?), thus incurring a performance penalty yet
again.
Any suggestions how this could be more efficient? Personally, I'd like
to see syntax directly in the engine to support this:
$c = new C;
$c->A::foo();
Though the static version "C::A::foo()" looks a little wierd....
-Brad Fisher
class D {
function bar() {
$c = new C;
// I'd like to call the A::foo method of C here...
// In PHP4, I could do something like:
Why should one want to do that? Why should PHP allow this?
$c is not an A, it is a C. Of course C is a special version of A, so it is
compatible to A. But it still is a C.
There will be a reason why C has overridden the A implementation of
foo(). It is possible that the original implementation is not compatible
to C, so it could be a risk to call the old method.
The feature you are asking for is not available in any OO language
and it even conflicts with the OOP ideology!
--
Ferdinand Beyer
<fb@fbeyer.com