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

Reply via email to