Re: An overloading question [message #174514 is a reply to message #174480] |
Wed, 15 June 2011 12:01 |
Thomas 'PointedEars'
Messages: 701 Registered: October 2010
Karma:
|
Senior Member |
|
|
sheldonlg wrote:
> 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
> --------------------------
> <?php
> abstract class A {
> public function b() {
> $this->a();
> }
> protected function a() {
> print 'In class A';
> }
> }
> ?>
>
> B.class.php
> ---------------------------
> <?php
> include_once 'A.class.php';
> class B extends A {
> public function a() {
> print 'In class B';
> }
> }
> ?>
>
> c.php
> ----------------------------
> <?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
<?php
abstract class A {
public function b() {
echo "A::b()\n";
$this->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
<?php
abstract class A {
public function b() {
echo "A::b()\n";
$this->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
|
|
|