Edit report at https://bugs.php.net/bug.php?id=61970&edit=1
ID: 61970
User updated by: postmaster at greg0ire dot fr
Reported by: postmaster at greg0ire dot fr
Summary: Restraining __construct() access level in subclass
gives a fatal error
Status: Open
Type: Bug
Package: Class/Object related
Operating System: Linux
PHP Version: 5.3.12
Block user comment: N
Private report: N
New Comment:
Perhaps I understood it one day, but now, I just can't recall why this example
could be a problem.
@cataphract: maybe you could elaborate? I think the expected behavior would be
the private constructor to be called when calling B::reset() ... To answer your
questions, I would definitely take the caller access into account when calling
the static methods.
Previous Comments:
------------------------------------------------------------------------
[2012-12-04 19:10:32] pwolfenden at qualys dot com
I don't understand why the example described on [2012-05-08 10:46 UTC] by
[email protected] poses a problem.
I would expect class B to inherit reset(), which remains public. So what?
The point of the factory pattern, for example, is precisely to force the use of
a single method to control the creation of new objects. And it is common OOP
practice to implement this pattern using protected constructor methods. So it
strikes me as bizzarre that PHP forces me to modify the whole class hierarchy
if
I want to enforce the use of a factory method for a derived class, and the base
class has a public constructor.
Thank you, greg0ire, for opening this bug.
------------------------------------------------------------------------
[2012-05-08 13:04:18] postmaster at greg0ire dot fr
Thanks for the detailed answer, it is very informative, especially the first
bit, which even shows the LSP could be applied in this case.
------------------------------------------------------------------------
[2012-05-08 10:46:42] [email protected]
It's true that PHP's behavior doesn't make a lot of sense from a theoretical
perspective. However, there are some practical reasons why a different behavior
would be -- arguably -- less desirable.
Namely, in PHP the constructor can be called from every instance method, even
after construction. This makes it a necessity that the constructor act like
regular instance methods. Consider:
<?php
class A {
private $a;
function __construct() { $this->a = new stdclass; }
function reset() { $this->__construct(); }
}
class B extends A {
private function __construct() { } //what of reset() now?
}
Plus, PHP allows enforcing constructor signatures via interfaces. This means
you have to enforce that signature throughout the hierarchy, and this includes
not allows changing the visibility of the constructor.
Similarly, there's no principled reason to be unable to reduce the visibility
in static methods. But PHP also prohibits such a pattern, like Java does, even
though there's no overriding (the method in the superclass is said to be
hidden). But PHP, like Java, allows calling static methods through an instance
and through the subclass name. Then if you call the reduced visibility static
method with the subclass name or a subclass instance, what would you do? Would
it depend on the access of the caller has to the subclass method?
------------------------------------------------------------------------
[2012-05-07 18:47:00] postmaster at greg0ire dot fr
fixed the title
------------------------------------------------------------------------
[2012-05-07 18:40:56] postmaster at greg0ire dot fr
Description:
------------
Restraining the __construct() method un a subtype gives a Fatal error.
As stated in the following resources, the LSP should not apply here.
- https://bugs.php.net/bug.php?id=40880
-
http://stackoverflow.com/questions/5490824/should-constructors-comply-with-the-liskov-substitution-principle
-
http://ralphschindler.com/2012/03/09/php-constructor-best-practices-and-the-prototype-pattern
Test script:
---------------
<?php
class Foo {
public function __construct(){}
}
class Bar extends Foo {
protected function __construct(){}
}
Expected result:
----------------
No output at all.
Actual result:
--------------
> PHP Fatal error: Access level to Bar::__construct() must be public (as in
> class Foo) in /tmp/bug.php on line 9
> Fatal error: Access level to Bar::__construct() must be public (as in class
> Foo) in /tmp/bug.php on line 9
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=61970&edit=1