Bug #61970 [Com]: Restraining __construct() access level in subclass gives a fatal error

From: Date: Tue, 01 Apr 2014 12:48:26 +0000
Subject: Bug #61970 [Com]: Restraining __construct() access level in subclass gives a fatal error
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-185002@lists.php.net to get a copy of this message
Edit report at https://bugs.php.net/bug.php?id=61970&edit=1

 ID:                 61970
 Comment by:         devoas at gmail dot com
 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:

There are some weak arguments here...

<?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?
}

Totally trivial case that fails to show anything at all. In reality child constructor can have
significantly different arguments and there are no complaints about that (as it should be), and now
supposedly such contrived case should mean anything? Why is LSP out with regards to arguments and
not with regards to access level? This makes absolutely no sense!

Also someone somewhere was talking about how php would not know which constructor to call if
child's one is private, if anyone wants to repeat this, this is also nonsense.

new B() --> Access exception, you see private constructor, stop looking, no need to dig to
parents as that would just lead to incorrect behavior anyways.


Previous Comments:
------------------------------------------------------------------------
[2012-12-04 20:35:23] postmaster at greg0ire dot fr

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.

------------------------------------------------------------------------
[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 
cataphract@php.net 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] cataphract@php.net

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

------------------------------------------------------------------------


The remainder of the comments for this report are too long. To view
the rest of the comments, please view the bug report online at

    https://bugs.php.net/bug.php?id=61970


-- 
Edit this bug report at https://bugs.php.net/bug.php?id=61970&edit=1


Thread (8 messages)

« previous php.bugs (#185002) next »