Переменные и расширение классов

korpus

злой бобёр
Не силён в ООП, поэтому столкнулся с этой особенностью только сейчас.

PHP:
<?php
error_reporting(E_ALL | E_STRICT);
ini_set("display_errors", "1");

class a
{
	private $_title='a-title';
	function echo_title()
	{
		echo $this->_title;
	}
}

$a = new a;
var_dump($a);

class b extends a
{
	private $_title='b-title';
	function echo_title()
	{
		echo $this->_title;
	}
}

$b = new b;
var_dump($b);
?>
<p>$_title в объекте a = <?php echo $a->echo_title(); ?></p>
<p>$_title в объекте b = <?php echo $b->echo_title(); ?></p>
Оказывается, что в одном классе может существовать сразу две переменных с одним именем. Это происходит. если один класс, содержащий эту переменную, расширить другим классом, в котором определить эту же самую переменную.

Такое поведение присуще и PHP5.2 и PHP5.3.
Как можно обращаться к таким "переопределяемым" переменным, чтобы знать наверняка, что выбирается именно нужная? Я может хочу обратиться к переменной, которая определена в классе a, но хочу сделать это из класса d, который создан последовательно расширением классов a, b, c.
И как данная особенность может быть использована в ООП на PHP? Я думаю, что это может только запутать. Так, столкнувшись с этим в Yii, я был запутан.
 

korpus

злой бобёр
Результат скрипта в PHP5.2.4, кстати, будет такой:

object(a)#1 (1) { ["_title:private"]=> string(7) "a-title" } object(b)#2 (2) { ["_title:private"]=> string(7) "b-title" ["_title:private"]=> string(7) "a-title" }
$_title в объекте a = a-title

$_title в объекте b = b-title


Отличие от PHP5.3 будет в том, что в PHP5.3 var_dump() показывает, от какого класса будет существовать переменная.
 

korpus

злой бобёр
Ничего не объясняет.
Вероятно, это какие-то особенности, которые существуют, но не объясняются явно в документации к PHP. Не очевидно, почему в PHP реализовано так, а не иначе. Мне вот непонятно, что делать с этим множеством переменных.
 

WMix

герр M:)ller
Партнер клуба
korpus
тогда попробуй логически поразмышлять. какое поведение ты ожидаешь от privat, думая о том что бывает еще и protected?
 

Ragazzo

TDD interested
флоппик
надо срочно двигаться в сторону симфони и все тащить оттуда, ну кроме дибильной идеи о метаданных в комментах :D
 

korpus

злой бобёр
korpus
тогда попробуй логически поразмышлять. какое поведение ты ожидаешь от privat, думая о том что бывает еще и protected?
Получается, что приватные переменные не "расширяются". "Защищённые" (protected) можно переопределять, но они не являются публичными и доступны внутри класса. Это истины, но с такой стороны я увидел их впервые.
Тогда что можно сказать насчёт методов классов? Я вот смог в классе b создать приватный метод с таким же именем, как и в классе a. Но в этом случае получается, что можно переопределять приватные методы. Поведение несколько отличается от того, что наблюдалось с переменными.
 

korpus

злой бобёр
Я тестировал такой код:
PHP:
<?php
error_reporting(E_ALL | E_STRICT);
ini_set("display_errors", "1");

class a
{
	protected $_title='a-title';
	function echo_title()
	{
		echo $this->get_title();
	}
	private function get_title()
	{
		return 'Из класса a: '. $this->_title;
	}
}

$a = new a;
var_dump($a);

class b extends a
{
	protected $_title='b-title';
	function echo_title()
	{
		echo $this->get_title();
	}
	private function get_title()
	{
		return 'Из класса b: '. $this->_title;
	}
}

$b = new b;
var_dump($b);
?>
<p>$_title в объекте a = <?php $a->echo_title(); ?></p>
<p>$_title в объекте b = <?php $b->echo_title(); ?></p>
Результат получился таким:
object(a)#1 (1) { ["_title:protected"]=> string(7) "a-title" } object(b)#2 (1) { ["_title:protected"]=> string(7) "b-title" }
$_title в объекте a = Из класса a: a-title

$_title в объекте b = Из класса b: b-title


Короче видно, что необходимо знать все эти особенности и понимать, что расширяя класс с названиями методов и переменных. как в родительском классе, программист расширяет объём своих проблем.
 

korpus

злой бобёр
Я думаю, здесь лучше реализовывать интерфесы, чем расширять классы таким образом.
 

korpus

злой бобёр
Подобную проблему в PHP5.3 пытались разрешить поздним статическим связываением. Там в примерах если посмотреть, то речь идёт о расширении классов с названиями одних и тех же методов.
ИМХО: Значит попросту по нормальному не надо использовать названия методов такие же, как и в расширяемых классах. И будет грамотная архитектура без всяких выворотов.

И действительно, зачем, расширяя класс нужно переопределять его методы и переменные? Логично будет тогда вовсе новый класс сделать, чем таким образом "доделывать" уже существующий.
 

WMix

герр M:)ller
Партнер клуба
korpus
PHP:
class a{
	private function _x(){ echo 'a-x'; }
	public function  ax(){ $this->_x(); }
}

class b extends a{
	private function _x(){ echo 'b-x'; }
	public function  bx(){ $this->_x(); }
}

$b = new b;
$b->ax();
$b->bx();

PHP:
class a{
	private $_x = 'a-x';
	public function  ax(){ echo $this->_x; }
}

class b extends a{
	private $_x = 'b-x';
	public function  bx(){ echo $this->_x; }
}

$b = new b;
$b->ax();
$b->bx();
 

korpus

злой бобёр
А о чём тогда там? Я читаю и вижу, что получается хрень, когда при расширении класса переопределяются его методы. Для решения связанных с этой хренью вопросов ввели позднее статическое связывание.
 

korpus

злой бобёр
korpus
PHP:
class a{
	private function _x(){ echo 'a-x'; }
	public function  ax(){ $this->_x(); }
}

class b extends a{
	private function _x(){ echo 'b-x'; }
	public function  bx(){ $this->_x(); }
}

$b = new b;
$b->ax();
$b->bx();

PHP:
class a{
	private $_x = 'a-x';
	public function  ax(){ echo $this->_x; }
}

class b extends a{
	private $_x = 'b-x';
	public function  bx(){ echo $this->_x; }
}

$b = new b;
$b->ax();
$b->bx();
Что это? Может быть лучше было так?

PHP:
class a{
    private function _x(){ echo 'a-x'; }
    public function  ax(){ $this->_x(); }
}

class b{
    private function _x(){ echo 'b-x'; }
    public function  bx(){ $this->_x(); }
}

$b = new b;
$b->ax();
$b->bx();
PHP:
class a{
    private $_x = 'a-x';
    public function  ax(){ echo $this->_x; }
}

class b {
    private $_x = 'b-x';
    public function  bx(){ echo $this->_x; }
}

$b = new b;
$b->ax();
$b->bx();
 

WMix

герр M:)ller
Партнер клуба
PHP:
class a{
	static private $_x = 'a-x';
	static public function  ax(){ echo self::$_x; }
}

class b extends a{
	static private $_x = 'b-x';
	static public function  bx(){ echo self::$_x; }
}
b::ax();
b::bx();
 

korpus

злой бобёр
Согласен. Только я уже про функции имел ввиду. С переменными мне стало ясно как действовать. Назначаем переменной protected и во всех расширяемых классах у нас получается одна переменная, доступ к которой всегда один $this->var.
А вот то что в расширяемом классе методы лучше не переопределять - это тоже вывод такой я сделал. Иначе путаница появляется, да и незачем это делать.
 
Сверху