ID: 48376 User updated by: kev dot simpson at gmail dot com Reported By: kev dot simpson at gmail dot com Status: Bogus Bug Type: Class/Object related Operating System: Windows XP Home PHP Version: 5.2.9 New Comment:
I'm not quite certain I follow you on this. As of 5.2.9-2 this behaviour only exists during a Grandfather > Father > Son relationship not during a standard parent > child relationship. This also covers any method including interface definitions and methods, not just constructors. Through my experience I have not been able to reduce the scope of any method in a child from a parent. The problem I see is that 1. A child of a single superclass cannot reduce any public functions; however, adding a grandparent superclass to the father with private scoping allows grandchildren to override their parent's scope. 2. Interfaces will be destroyed. If the 'Father' or first child class is implementing the interface while the GrandParent class defines the same as private allowing a grandchild to decay its scope to private. This always results in an uncatchable fatal error when the method is called, even though the 'son' is considered an instanceof the given interface. I don't think that an interfaced class (or any class extending an interfaced class) should have a private / protected declaration of the contracted methods by the interface. Don't get me wrong, I love the idea of being able to reduce the scope of a constructor in an extending class in order to develop singleton and similar objects. However, the inability to try/catch a fatal error on an interfaced method is IMO a bug. Here is a little more code to show what I mean: <?php ini_set('display_errors', 1); error_reporting(E_ALL); interface IInterface { public function test(); } class Grandfather { private function __construct() { } private function test() { printf("%s\n", __METHOD__); } } class Father extends Grandfather implements IInterface { public function __construct() { printf("%s\n", __METHOD__); } public function test() { printf("%s\n", __METHOD__); } } class Son extends Father { protected function __construct() { parent::__construct(); printf("%s\n", __METHOD__); } public static function createInstance() { return new self; } protected function test() { parent::test(); printf("%s\n", __METHOD__); } } class CorrectScope implements IInterface { public function __construct() { printf("%s\n", __METHOD__); } public function test() { printf("%s\n", __METHOD__); } } $t = Son::createInstance(); var_dump($t); if ($t instanceof IInterface) { print("\$t is an IInterface, check test:\n"); // Fatal error on an interface call printf("Results of \$t->test() = %s\n", $t->test()); } // Below is what I expect to happen with a parent > child relationship class CorrectScopeChild extends CorrectScope { // Cannot reduce to protected/private public function __construct() { printf("%s\n", __METHOD__); } // Cannot reduce to protected/private public function test() { parent::test(); printf("%s\n", __METHOD__); } } $correct = new CorrectScopeChild(); $correct->test(); ?> So this adds another question. How do we deal with interfaced classes that don't have access to the contracted methods? If we can't try/catch the calls resulting in fatal termination, I consider this to be a bug. Previous Comments: ------------------------------------------------------------------------ [2009-05-24 17:58:53] johan...@php.net Thank you for taking the time to write to us, but this is not a bug. Please double-check the documentation available at http://www.php.net/manual/ and the instructions on how to report a bug at http://bugs.php.net/how-to-report.php We decided to do less strict checking on the constructor. So this is the way it is meant to be. ------------------------------------------------------------------------ [2009-05-24 17:14:07] kev dot simpson at gmail dot com Description: ------------ Tested in 5.2.5, 5.2.9-2 and 6.0.0-dev using Apache 5.0.59 When a class uses a private scope on a method, any grandchild class can demote the scope regardless of what the primary class's immediate child scope is. Curious if I can exploit this as a feature or if it is indeed a bug. Example is in order to help visualize. Reproduce code: --------------- <?php class TestParent { private function __construct() { } } class Child extends TestParent { public function __construct() // Ok, parent is private and unviewable, so not technically overridding { printf("%s\n", __CLASS__); } } class GrandChild extends Child { protected function __construct() // Override here; scope reduction is prohibited in PHP { parent::__construct(); printf("%s\n", __CLASS__); } public static function createInstance() { return new self; } } GrandChild::createInstance(); ?> Expected result: ---------------- I expect this to produce a fatal error indicating that 'Access level to GrandChild::__construct() must be public (as in Child) in ....' Actual result: -------------- Child GrandChild Returning of object of instance GrandChild. ------------------------------------------------------------------------ -- Edit this bug report at http://bugs.php.net/?id=48376&edit=1