Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > PHP: Общие вопросы > PHP5, OOP: общее свойство


Автор: Canarat 11.3.2008, 15:50
Приветствую.
Код

<?php
class Class1
{
   function __construct()
   {
      $this->Req = new Class2 ;
      $this->Typo = new Class3 ;
      $this->Typo->cl = & $this ;
   }
}
class Class2
{
   protected $counter = 0 ;
   function change()
   {
      $this->counter += 1 ;
   }
}
class Class3
{
   function change()
   {
      $this->cl->Req->change() ;
   }
}
$cl = new Class1 ;
echo var_dump($cl->Req) ;
$cl->Req->change() ;
echo var_dump($cl->Req) ;
$cl->Req->change() ;
echo var_dump($cl->Req) ;
$cl->Typo->change() ;
echo var_dump($cl->Req) ;
$cl->Typo->change() ;
echo var_dump($cl->Req) ;
$cl->Typo->change() ;
?>

Выдает следующий результат:
Код

object(Class2)[7]
  protected 'counter' => int 0

object(Class2)[7]
  protected 'counter' => int 1

object(Class2)[7]
  protected 'counter' => int 2

object(Class2)[7]
  protected 'counter' => int 2

object(Class2)[7]
  protected 'counter' => int 2


Т.е. в последних трех вызовах не происходит никаких изменений. Мне кажется такое поведение нелогично, если я ошибаюсь - можно ли это как-то объяснить или нужно задействовать другой способ вызова?

Автор: solenko 11.3.2008, 18:20
Какая версия php?
У меня на 5.2.1 ожидаемое поведение (от 1 до 4)

Автор: Vaulter 11.3.2008, 19:32
Цитата


object(Class2)#2 (1) {
  ["counter:protected"]=>
  int(0)
}
object(Class2)#2 (1) {
  ["counter:protected"]=>
  int(1)
}
object(Class2)#2 (1) {
  ["counter:protected"]=>
  int(2)
}
object(Class2)#2 (1) {
  ["counter:protected"]=>
  int(3)
}
object(Class2)#2 (1) {
  ["counter:protected"]=>
  int(4)
}
vaulter@vaulter-desktop:~$ php -v
PHP 5.2.3-1ubuntu6 (cli) (built: Oct  4 2007 23:35:54)
Copyright © 1997-2007 The PHP Group
Zend Engine v2.2.0, Copyright © 1998-2007 Zend Technologies


Автор: Canarat 11.3.2008, 19:55
PHP 5.1.6, на серверах такая же. Что мне с ней поделать?

Автор: vasac 11.3.2008, 22:19
А class3 тут причем?

Автор: SelenIT 12.3.2008, 01:56
У меня (5.2.1 под WinXP) результат такой же, как у Vaulterа. Но вообще само обращение к $this->cl без объявления этой самой public $cl выглядит странно и непривычно...

Автор: N0dwis 12.3.2008, 09:08
 smile 
А можно узнать в чем суть таких телодвижений? Чисто академический интерес?

Автор: Canarat 12.3.2008, 13:44
N0dwis, в какой-то мере да, я в поисках оптимальной структуры взаимодействия не классов, а объектов.
SelenIT, объявление не помогает, поведение аналогично, хотя выглядит все более прозрачно.
vasac, я просто показал, что в системе из трех объектов, два из которых связаны с первым, но не связаны друг с другом, третий обьект не может изменить второй через жесткую ссылку на первый.

Я прошу тех, у кого 5.2, проверить результаты на 5.1.х, чтобы мои опасения подтвердились.

Автор: N0dwis 12.3.2008, 15:46
Проверил у себя на 5.2.4 - тоже работает нормально.
Но по-моему ты все таки ерундой занимаешься. Все ООП создавалось для того, чтобы отделить разные сущности друг от друга. Инкапсуляция! А ты пытаешься сделать наоборот.

Автор: solenko 12.3.2008, 18:02
N0dwis, ерундой-не не важно. Скрипт ведет себя неожиданным образом, это недокументировано, а значит это либо баг либо фича о которой полезно знать. Если бы никто не занимался фигней, то до сих пор сидели бы мы с php3

Добавлено через 5 минут и 24 секунды
Код

php test.php 0-246 ~]$
object(Class2)#2 (1) {
  ["counter:protected"]=>
  int(0)
}
object(Class2)#2 (1) {
  ["counter:protected"]=>
  int(1)
}
object(Class2)#2 (1) {
  ["counter:protected"]=>
  int(2)
}
object(Class2)#2 (1) {
  ["counter:protected"]=>
  int(3)
}
object(Class2)#2 (1) {
  ["counter:protected"]=>
  int(4)
}
php -ver@leto0-246 ~]$
PHP 5.2.0 (cli) (built: Apr 11 2007 02:16:27)
Copyright (c) 1997-2006 The PHP Group
Zend Engine v2.2.0, Copyright (c) 1998-2006 Zend Technologies


Автор: solenko 12.3.2008, 18:18
Вобщем не знаю как это у вас получилось -- у меня так не получается
Код

[]$ php < bug.php
object(Class2)#2 (1) {
  ["counter:protected"]=>
  int(0)
}
object(Class2)#2 (1) {
  ["counter:protected"]=>
  int(1)
}
object(Class2)#2 (1) {
  ["counter:protected"]=>
  int(2)
}
object(Class2)#2 (1) {
  ["counter:protected"]=>
  int(3)
}
object(Class2)#2 (1) {
  ["counter:protected"]=>
  int(4)
}
[]$ php -v
PHP 5.1.6 (cli) (built: Sep 25 2006 09:11:22)
Copyright (c) 1997-2006 The PHP Group
Zend Engine v2.1.0, Copyright (c) 1998-2006 Zend Technologies

Автор: Canarat 12.3.2008, 19:11
solenko, 
Может суть в том, что у меня не cli версия?

Именно недокументированное поведение меня и смущает, т.к. после этого инцидента я пересматривать буду структуру в соответствии с теорией дзен-буддизма и философией постулатов ООП.

Автор: SelenIT 12.3.2008, 19:18
Цитата(N0dwis @  12.3.2008,  15:46 Найти цитируемый пост)
Все ООП создавалось для того, чтобы отделить разные сущности друг от друга. Инкапсуляция! А ты пытаешься сделать наоборот. 

Имхо, все нормально - такая композиция объектов, при которой объект-часть знает, чей он (вроде свойства form у элемента формы в JS), имеет право на жизнь и во многих случаях оправдана.

Canarat, а каких-нибудь Zend Accelerator'ов и т.п. у тебя часом не стоит? Особенно старых версий, заточенных еще под ZE1?

Автор: Canarat 12.3.2008, 19:56
SelenIT, никаких надстроек и нестандартных библиотек. Есть xDebug, но это из другой оперы.

Автор: N0dwis 16.3.2008, 16:59
Еще раз посмотрел внимательно код, смутила одна строчка,
Код

      $this->Typo->cl = & $this ;

Насколько я знаю, в php5 операция & практически бессмысленна (уточните, если я ошибаюсь), все объекты и так передаются через указатели. Если подходить формально, то ты присваиваешь переменной $cl значение адреса переменной $this, но никак не значение адреса объекта. Попробуй так, вдруг получится:
Код

      $this->Typo->cl = $this ;

Автор: flashaa 16.3.2008, 17:25
N0dwis, это без разницы. Во всех скриптах для PHP4 оставлен указатель. При этом на PHP5 все скрипты с амперсендом прекрасно работают. Взять хотя бы PEAR. Да, этот знак избыточен, но он не может быть причиной ошибки. Потом, такие слова как адрес в PHP вообще не имеют смысла, в C, Delphi - да, а  в PHP это просто прием, который позволяет двум переменным ссылаться на одну ячейку памяти. 

Автор: Canarat 16.3.2008, 18:08
В общем выяснились некоторые подробности, касательно РНР разработчика, использовавшего мой сервер некоторое время.

Все дело в ze1.compatibilty_mode(хотя Zend Accelerator не подключен), строчке из php.ini, я не обратил внимания на неё когда SelenIT сделал предположение.

Но такое построение кода достаточно тривиально, и не уверен, что оно могло измениться с ze1 до ze2. Может, все-таки, баг?

Автор: N0dwis 16.3.2008, 21:12
Цитата(flashaa @  16.3.2008,  17:25 Найти цитируемый пост)
Потом, такие слова как адрес в PHP вообще не имеют смысла, в C, Delphi - да, а  в PHP это просто прием, который позволяет двум переменным ссылаться на одну ячейку памяти.  

Ну да, но суть-то такая же... А как по другому это назвать?  smile 

Цитата(Canarat @  16.3.2008,  18:08 Найти цитируемый пост)
Может, все-таки, баг? 

Canarat, не баг. Я включил у себя zend.ze1_compatibility_mode - результат тот же, что и у тебя! В последних 3-х случаях не происходит приращение счетчика! Буду копать дальше.

Автор: Canarat 16.3.2008, 21:28
N0dwis, я имею в виду именно баг PHP с такими настройками.

Автор: N0dwis 16.3.2008, 21:52
"Ну, барин, ты задачи ставишь!" (с) к/ф "Формула любви".
НАШЕЛ!
Не глюк и не баг, все работает, как и должно. По этому поводу есть и статья в документации References inside the constructor.
И если подправить код вот так:
Код

...
$cl = & new Class1;
echo var_dump($cl->Req);
...

то все работает!
Оказывается, конструктор возвращает не сам созданный объект, а его копию! Т.е. $this в конструкторе и результат new Class1 - это не одно и то же! А чтобы было одним и тем же, нужно использовать не оператор копирования (=), а оператор получения ссылки (= &) (Это практически цитата из документации).
 smile 

Блин, полезно все-таки иногда вдумчиво читать инструкции...

Автор: flashaa 16.3.2008, 22:08
N0dwis, если ты про это - http://www.php.net/manual/ru/language.oop.newref.php ,
то оно относится к PHP 4, и это справедливо для любых операций, где присваиваются объекты в PHP 4. В 4ке передаются копии объектов. В 5ой версии все объекты передаются по ссылкам, в т.ч. возвращаемое конструктором значение $this.

Автор: N0dwis 16.3.2008, 22:15
Цитата(flashaa @  16.3.2008,  22:08 Найти цитируемый пост)
N0dwis, если ты про это - http://www.php.net/manual/ru/language.oop.newref.php

Именно про это. Canarat, ведь сказал, что у него php работает в режиме совместимости с 4-й.

Автор: flashaa 16.3.2008, 22:18
N0dwis, молодца. Точно, с такой опцией передаются копии объектов как в PHP4 и амперсенд в самый раз.
Цитата

  zend.ze1_compatibility_mode  boolean

    Включает режим совместимости с Zend Engine 1 (PHP 4). Это влияет на клонирование, приведение типов и сравнение объектов. 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)