Path: csiph.com!x330-a1.tempe.blueboxinc.net!aioe.org!feeder.news-service.com!kanaga.switch.ch!news-zh.switch.ch!switch.ch!news.belwue.de!newsfeed.arcor.de!newsspool4.arcor-online.net!news.arcor.de.POSTED!not-for-mail Content-Type: text/plain; charset="UTF-8" Message-Id: <2975511.SPkdTlGXAF@PointedEars.de> From: Thomas 'PointedEars' Lahn Reply-To: Thomas 'PointedEars' Lahn Organization: PointedEars Software (PES) Date: Wed, 15 Jun 2011 14:01 +0200 User-Agent: KNode/4.4.7 Content-Transfer-Encoding: 8Bit Subject: Re: An overloading question Newsgroups: comp.lang.php References: MIME-Version: 1.0 Lines: 220 NNTP-Posting-Date: 15 Jun 2011 14:01:31 CEST NNTP-Posting-Host: f0f8fe46.newsspool4.arcor-online.net X-Trace: DXC=0?oH;a6I[9jfF8a^:6>b7e4IUK I have a problem that I am wrestling with that should be so obvious and > easy -- but it isn't. I have a base class that has a method that calls > another method in the base class with $this->thatOtherMethod. I have > another class that extends the base class and I want to have > thatOtherMethod in the extended class override the one in the base > class. The calling method in the base class is called using and > instance of the extended class pointing to that method. > > Simply, here is an example: > > A.class.php > -------------------------- > abstract class A { > public function b() { > $this->a(); > } > protected function a() { > print 'In class A'; > } > } > ?> > > B.class.php > --------------------------- > include_once 'A.class.php'; > class B extends A { > public function a() { > print 'In class B'; > } > } > ?> > > c.php > ---------------------------- > include 'B.class.php'; > $x = new B(); > $x->b(); > ?> > ---------------------------- > > I want it to print out "In class B", but it prints out "In class A". > > I have looked over Google quite a bit and found nothing that helped. I > have tried making the methods public, protected, keep them both the same > access, etc. and have had no luck. Suggestions? Yes. Both your testing method and your posting leave much to be desired: You should have avoided the `include's in the test code, thereby removing them from the equation and making it easier for people to test your code. They are deprecated for class loading anyway (at least by PEAR standards; use an autoloader instead). [But if you must use includes in this context, you should use `require_once' instead.] You should have added at least one output statement to *each* method, and between the global statements. [You should have used `echo' instead of `print', since you are not using print's return value.] You should not have named the method case-insensitively the same as the class, as that can make a constructor out of the method. [But if that was your intention, you should have used exactly the same name – considering letter case – or (better since PHP 5) __construct.] You should have said which PHP client (version, type) you have been testing with. Finally, in retrospect of my results below, you should have been more precise as to the output you are getting. Using a variant of your code that meets these criteria – $ cat overloading.php a(); } protected function a() { echo "A::a()\n"; } } class B extends A { public function a() { echo "B::a()\n"; } } echo "instantiation\n"; $x = new B(); echo "method call\n"; $x->b(); ?> –, I cannot confirm your observations here exactly: $ php overloading.php instantiation PHP Fatal error: Call to protected A::a() from invalid context in ****/overloading.php on line 21 PHP Stack trace: PHP 1. {main}() ****/overloading.php:0 $ php --version PHP 5.3.3-7+squeeze1 with Suhosin-Patch (cli) (built: Mar 18 2011 17:22:52) Copyright (c) 1997-2009 The PHP Group Zend Engine v2.3.0, Copyright (c) 1998-2010 Zend Technologies with XCache v1.3.1, Copyright (c) 2005-2010, by mOo with Xdebug v2.1.0, Copyright (c) 2002-2010, by Derick Rethans with Suhosin v0.9.32.1, Copyright (c) 2007-2010, by SektionEins GmbH But with the Apache 2.0 module of PHP 5.3.3-7+squeeze1 on the same computer, I am not getting this error for the same code; instead I get the following output (taken from the View Source window in the browser, Iceape 2.0.14): instantiation method call A::b() B::a() If the visibility of A::a() is changed to `public' – $ cat overloading2.php a(); } public function a() { echo "A::a()\n"; } } class B extends A { public function a() { echo "B::a()\n"; } } echo "instantiation\n"; $x = new B(); echo "method call\n"; method call A::b() B::a() $x->b(); ?> – I get the following with the CLI: $ php overloading2.php instantiation A::a() method call A::b() B::a() But with the Apache 2.0 module, I get: instantiation method call A::b() B::a() A possible explanation for the CLI behavior is that, because B has no constructor, and A::b() is not inherited as constructor for B, but B is to be instantiated, the constructor of its superclass A, A::a(), is called instead (regardless whether that class is declared abstract, as it would not be instantiated). This reasoning would be consistent with the fact that it is a fatal error when that constructor, A::a(), is not public. [It certainly has *nothing* to do that PHP would not being able to call methods of instantiated classes properly, i.e. does not implement "virtual" methods. Although it does have OO deficiencies, PHP can do that well. And *no* OOPL I know lets classes inherit constructors.] If that applies, then the reason why you are not getting an error, and I am not getting an error with the Apache 2.0 module, could be that (perhaps through php.ini settings) the Apache 2.0 module enforces other (in my case: stricter) rules than the CLI, since the PHP versions are the same here. This reasoning would be consistent with the fact that, regardless whether A::a() is public or not, it is not called when using the Apache 2.0 module; we can assume B is considered to have an implicit empty constructor, B::__construct(), then (as A cannot be instantiated). Then B::a() is called because A::b() can be and is inherited by B from A (it sort of becomes B::b() for instances of B), and A/B::b() calls B::a() accordingly, regardless whether A::a() it is public or not (as A::a() is not called in the first place). [Suppose a php.ini setting is the reason for this difference, I would be grateful if someone pointed me to the relevant documentation.] While that would explain why you are not getting an error, it would not explain why – as you stated – *only* A::a() would be called in any case. A possible explanation for that would be that you were using a different, perhaps older, version of PHP. In that case upgrading PHP might be a good idea. HTH PointedEars -- Anyone who slaps a 'this page is best viewed with Browser X' label on a Web page appears to be yearning for the bad old days, before the Web, when you had very little chance of reading a document written on another computer, another word processor, or another network. -- Tim Berners-Lee