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

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to