Примечание: следующее было протестировано с PHP 5.3.8. Другие версии могут вести себя иначе.
Поскольку для PHP нет формальной спецификации, нет способа ответить на этот вопрос с точки зрения того, что должно произойти. Самое близкое, что мы можем получить, - это утверждение о protected из руководства по PHP:
Members declared protected can be accessed only within the class itself and by inherited and parent classes.
Хотя член может быть переопределен в ChildClass
(сохраняя спецификатор «protected»), он был первоначально объявлен в BaseClass
, поэтому он остается видимым в потомках BaseClass
.
В противовес этой интерпретации сравните поведение охраняемого объекта:
<?php
abstract class BaseClass {
protected $_foo = 'foo';
abstract protected function __construct();
}
class MommasBoy extends BaseClass {
protected $_foo = 'foobar';
protected function __construct(){
echo __METHOD__, "\n";
}
}
class LatchkeyKid extends BaseClass {
public function __construct() {
echo 'In ', __CLASS__, ":\n";
$kid = new MommasBoy();
echo $kid->_foo, "\n";
}
}
$obj = new LatchkeyKid();
Выход:
In LatchkeyKid:
MommasBoy::__construct
Fatal error: Cannot access protected property MommasBoy::$_foo in - on line 18
Изменение абстрактного __construct
на конкретную функцию с пустой реализацией дает желаемое поведение.
abstract class BaseClass {
protected function __construct() {}
}
Однако немагические методы видны в родственниках, независимо от того, являются ли они абстрактными (большинство магических методов должны быть общедоступными).
<?php
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() {
echo 'In ', __CLASS__, ":\n";
$kid = new MommasBoy();
echo $kid->abstract_protected(), "\n", $kid->concrete(), "\n";
}
}
$obj = new LatchkeyKid();
Выход:
In LatchkeyKid:
MommasBoy::abstract_protected
MommasBoy::concrete
Если вы проигнорируете предупреждения и объявите магические методы (кроме __construct
, __destruct
и __clone
) как protected
, они окажутся доступными в родственниках, как и в случае с немагическими методами.
Защищенные __clone
и __destruct
недоступны в родственниках, независимо от того, являются ли они абстрактными. Это заставляет меня думать, что поведение abstract __construct
является ошибкой.
<?php
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();
Выход:
In LatchkeyKid:
Fatal error: Call to protected MommasBoy::__clone() from context 'LatchkeyKid' in - on line 16
Доступ к __clone
осуществляется в zend_vm_def .h (в частности, _ 17_ обработчик кода операции). Это в дополнение к проверкам доступа к методам, что может быть причиной различного поведения. Однако я не вижу специальной обработки для доступа к __destruct
, так что очевидно, что это еще не все.
Стас Малышев (привет, Стас!), Один из разработчиков PHP, взглянул на __construct
, __clone
и __destruct
и сказал следующее:
В общем, функция, определенная в базовом классе, должна быть доступна всем [потомкам] этого класса. Обоснование этого состоит в том, что если вы определяете функцию (даже абстрактную) в своем базовом классе, вы говорите, что она будет доступна для любого экземпляра (включая расширенные) этого класса. Таким образом, любой потомок этого класса может его использовать.
[...] Я проверил, почему ctor ведет себя по-другому, и это потому, что родительский ctor считается прототипом для дочернего ctor (с принудительной подписью и т. Д.), Только если он объявлен абстрактным или получен из интерфейса. Итак, объявив ctor абстрактным или сделав его частью интерфейса, вы сделаете его частью контракта и, таким образом, доступным для всей иерархии. Если вы этого не сделаете, ctors полностью не связаны друг с другом (это отличается для всех других нестатических методов), и, таким образом, родительский ctor ничего не говорит о дочернем ctor, поэтому видимость родительского ctor не переносится. Так что для ctor это не ошибка. [Примечание: это похоже на ответ Дж. Бруни.]
Я все еще думаю, что это, скорее всего, ошибка __clone и __destruct.
[...]
Я отправил ошибку № 61782, чтобы отследить проблему с __clone и __destruct.
person
outis
schedule
24.02.2012
BaseClass
находится там, где определен конструктор (что на самом деле и есть), следовательно, согласно правилам наследованияParentClass
имеет к нему доступ. Ошибка? Спорный. Редкий крайний случай? Безусловно. - person deceze♦   schedule 24.02.2012abstract
спецификация, так что, возможно, именно здесь и определен метод. - person deceze♦   schedule 24.02.2012BaseClass::__construct
определенprotected
,ChildClass::__construct
наследует это без изменения,ParentClass::__construct
наследует отBaseClass
, поэтомуParentClass
имеет доступ кChildClass::__construct
. - person deceze♦   schedule 24.02.2012abstract
методов, не от которых наследуется класс.BaseClass
определяет метод__construct
и его видимость,ChildClass
просто реализует его ... - person deceze♦   schedule 24.02.2012