Re: [PHP-DEV] Access by siblings of (abstract) protected methods

2012-04-20 Thread Stas Malyshev
Hi!

 In summary: should abstract protected constructors be inaccessible by
 siblings, as is true of __clone and __destruct? Should __construct, __clone
 and __destruct always be accessible in relatives, as is true of other
 methods? Depending on the answers, there could be a documentation issue, or
 bugs.

I've submitted bug #61782 (https://bugs.php.net/bug.php?id=61782) to
track the issue with __clone and __destruct.
-- 
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



[PHP-DEV] Access by siblings of (abstract) protected methods

2012-04-05 Thread Galen Wright-Watson
Last month, Ahmad Farouk asked a question on StackOverflow about siblings
accessing protected methods http://stackoverflow.com/q/9425770/90527 (
http://stackoverflow.com/q/9425770/90527) in PHP (I've been using 5.3.8 on
OS X; others haven't mentioned which versions they've tested). He was
surprised at the current behavior, where whether a constructor was
abstract, or concrete in an abstract parent class, or in a concrete parent
class affected whether or not a child class could be instantiated in
sibling classes. All of us involved in the QA were wondering what the
appropriate behavior should be.

The documentation for protected http://php.net/protected states in the
first paragraph on visibility:

 Members declared protected can be accessed only within the class itself
 and by inherited and parent classes.


Bug 37632 https://bugs.php.net/bug.php?id=37632 (protected methods not
accessible by siblings) suggests that protected methods should be
accessible by all relatives, not just ancestors and descendants. The actual
behavior is different from either of these (and apparently inconsistent).
Here's a breakdown of the current behavior, as far as I can discern:

* Protected properties in a child class that hide a parent's property can't
be accessed in siblings (which I don't find surprising, but may be
erroneous).

* Protected constructors declared abstract in a parent can be accessed in
sibling classes.

abstract class BaseClass {
abstract protected function __construct();
}
class MommasBoy extends BaseClass {
protected function __construct(){
echo __METHOD__, \n;
}
}
class LatchkeyKid extends BaseClass {
public function __construct() {
echo 'In ', __CLASS__, :\n;
$kid = new MommasBoy();
}
}
$obj = new LatchkeyKid();

  Result:

In LatchkeyKid:
 MommasBoy::__construct


* Concrete protected constructors can't be accessed in sibling classes,
whether the parent is abstract or concrete. Remove the abstract from
BaseClass::__construct and add an empty body in the above code, and the
result is a fatal error: Call to protected MommasBoy::__construct() from
context 'LatchkeyKid'. Further, remove abstract from BaseClass, and this
same fatal error results.

* Protected __clone and __destruct are not accessible in siblings, whether
or not they're abstract.

abstract class BaseClass {
abstract protected function __clone();
}

class MommasBoy extends BaseClass {
protected function __clone() {
echo __METHOD__, \n;
}
}

class LatchkeyKid extends BaseClass {
public function __construct() {
echo 'In ', __CLASS__, :\n;
$kid = new MommasBoy();
$kid = clone $kid;
}
public function __clone() {}
}

$obj = new LatchkeyKid();

  Result:

 In LatchkeyKid:
 Fatal error: Call to protected MommasBoy::__clone() from context
 'LatchkeyKid'


  Making __clone concrete in the above code has no affect on the behavior;
the same error is raised.

* Non-magic methods are accessible in relatives, whether they're abstract
or concrete in a parent.

abstract class BaseClass {
abstract protected function abstract_protected();
protected function concrete() {}
}

class MommasBoy extends BaseClass {
/* accessible in relatives */
protected function abstract_protected() {
return __METHOD__;
}
protected function concrete() {
return __METHOD__;
}
}

class LatchkeyKid extends BaseClass {
function abstract_protected() {}
public function __construct() {
$kid = new MommasBoy();
echo $kid-abstract_protected(), \n, $kid-concrete(), \n;
}
}

$obj = new LatchkeyKid();

Result:

 In LatchkeyKid:
 MommasBoy::abstract_protected
 MommasBoy::concrete


* Most magic methods must be public, so protected access is moot. If you
declare magic methods (other than __construct, __destruct and __clone) as
protected and ignore any warnings that the method must be public, they
appear to be accessible in relatives, as with non-magic methods.

The behavior of protected __construct is the odd one out. Except for the
abstract protected case, it behaves as __clone and __destruct, whereas I
would have expected __construct to *always* behave as __clone and
__destruct. The behavior of __clone and __destruct is itself somewhat
surprising, as it differs from other methods. It could be considered to be
a bug along the lines of bug 37632 https://bugs.php.net/bug.php?id=37632,
but only affecting these three magic methods. For a reason why this could
be buggy behavior, consider the following code:

abstract class BaseClass {
abstract protected function __clone();
}

class MommasBoy extends BaseClass {
protected function __clone() {
echo __METHOD__, \n;
}
}