Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:7933 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 70416 invoked by uid 1010); 17 Feb 2004 20:01:22 -0000 Delivered-To: ezmlm-scan-internals@lists.php.net Delivered-To: ezmlm-internals@lists.php.net Received: (qmail 70392 invoked from network); 17 Feb 2004 20:01:22 -0000 Received: from unknown (HELO mail.info-link.net) (65.122.208.20) by pb1.pair.com with SMTP; 17 Feb 2004 20:01:22 -0000 Received: from info-link.net (spooler.info-link.net [65.122.208.6]) by mail.info-link.net (8.12.10/8.12.10) with ESMTP id i1HK1KN5027384 for ; Tue, 17 Feb 2004 14:01:20 -0600 Message-ID: <40327310.74714A7C@info-link.net> Date: Tue, 17 Feb 2004 14:01:20 -0600 Organization: Info Link Inc. X-Mailer: Mozilla 4.79 [en] (Win98; U) X-Accept-Language: en,pdf MIME-Version: 1.0 To: internals@lists.php.net Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit X-ConnInfo-Version: Connection info milter (v0.5) running on milter.info-link.net if_addr=65.122.208.20 if_name=mail.info-link.net offical_name=mail.info-link.net pid=27384 X-ConnInfo: relay_addr=65.122.208.6 relay_name=spooler.info-link.net relay_helo=info-link.net milter_time=200402171401 queue_id=i1HK1KN5027384 message_id=<40327310.74714A7C@info-link.net> X-AntiVirus: checked by Vexira Milter 1.0.6; VAE 6.24.0.4; VDF 6.24.0.7 Subject: Calling methods of parent/ancestor classes in PHP5 From: brad@info-link.net (Brad Fisher) 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