2014-02-21 3 views
1

Я пытаюсь использовать this trick для доступа к частной переменной базового класса из дочернего класса, но я не совсем понимаю закрытие, поэтому у меня возникают проблемы. Следующий пример почти работает, за исключением того, что я привязываюсь к новому экземпляру родительского класса вместо экземпляра дочернего класса.Использование Closure :: bind в дочернем классе

class Kitchen 
{ 
    private $yummy = 'cake'; 

    public function change_treat() 
    { 
     $yummy = 'pie'; 
    } 
} 

class pantry extends Kitchen 
{ 


    public function FindFood() 
    { 

     $yum = function() 
     { 
      return $this->yummy; 
     }; 

     $kit = new Kitchen(); 
     $yumers = Closure::bind($yum, $kit, $kit); 
     echo "Look, a " . $yumers(). "!\n"; 
    } 
} 

$p = new pantry(); 
$p->FindFood(); 
$p->change_treat(); 
$p->FindFood(); 

Выход:

Look, a cake! 
Look, a cake! 

Желаемая Выход:

Look, a cake! 
Look, a pie! 

Я понимаю, почему мой код выхода cake дважды. Это потому, что я создаю полностью отдельный объект Кубы, когда я связываю закрытие. У меня возникли проблемы с выяснением, что нужно передать в closure::bind, чтобы сказать «привязаться к моему родителю», или если то, что я делаю, возможно. Есть предположения?

Спасибо.

Редактировать: Для тех из вас, кто поделился вашей озабоченностью по поводу этой техники, я понимаю, что это нарушает инкапсуляцию и не рекомендуется. Пока это доказательство концепции. Ситуация в том, что у меня есть плагин Wordpress, который имеет функциональность, которую я хотел бы расширить. Эта часть плагина не имеет крючков, поэтому я пытаюсь найти другие способы ее расширения. Одна из переменных является частной, и мне нужно проверить ее, чтобы определить, следует ли вызывать родительский метод или использовать мою собственную логику. Я знаю, что это звучит сомнительно, и я буду рассматривать это как попытку «резинки и клейкой ленты». Я планирую сообщить разработчику плагина, что я пробовал, и что может облегчить работу с плагином.

ответ

0

Прежде всего, ваш код здесь не так:

public function change_treat() 
{ 
    $yummy = 'pie'; 
} 

Оно должно быть:

public function change_treat() 
{ 
    $this->yummy = 'pie'; 
} 

В противном случае, вы бы просто быть назначая значение функции локальной переменной, отбрасывается, когда это делается.

Во-вторых, при каждом вызове pantry::FindFood() вы создаете новый экземпляр Kitchen, который затем привязывает к закрытию.

, как вы могли бы решить это путем разрыва цепи наследования:

class pantry 
{ 
    private $kitchen; 

    function __construct(Kitchen $kitchen) 
    { 
     $this->kitchen = $kitchen; 
    } 

    function findFood() 
    { 
     $yum = function() { 
      return $this->yummy; 
     }; 

     $kit = new Kitchen(); 
     $yumers = Closure::bind($yum, $this->kitchen, $this->kitchen); 
     echo "Look, a " . $yumers(). "!\n"; 
    } 
} 

$k = new Kitchen(); 
$p = new pantry($k); 

$p->FindFood(); 
$k->change_treat(); 
$p->FindFood(); 

Это сказал, что лучше не используйте этот хак на все и исправить Kitchen classby добавления поглотителя, например getYummy().

+0

Исправление этой ошибки [все еще не работает] (http://3v4l.org/MP3Ub). Однако, используя рефлексию [делает] (http://3v4l.org/U0R2X) (хотя основное внимание по-прежнему стоит: пожалуйста, не делайте этого) – DaveRandom

+0

Это работает, если вы используете Closure :: bind ($ yum, $ this- > кухня, $ this-> кухня) ;. Я отредактировал сообщение, чтобы это отразить. Я посмотрю, будет ли это работать в моем сценарии и принять его, если это произойдет. – VanillaBean

+0

@ VanillaBean Правильно, вот что я намеревался написать на самом деле :) –

0

Я знаю, что создание новой кухни, если FindFood означает, что я получу пирог, и эта часть ошибочна. То, что я прошу, есть, что я передаю для закрытия :: bind для привязки к экземпляру родительской кухни вместо экземпляра Pantry.

пересмотренный ответ:

В вашем примере кода, закрытие делает привязку к экземпляру Kitchen вы создаете в FindFood. Вот где вы получаете значение «торт».Когда вы вызываете change_treat, вы изменяете значение $yummy в своем Pantry объекте. Значение в объекте Kitchen не изменяется.

<?php 
class kitchen{ 

    private $_yummy = "cake"; 

    public function change_yummy($newvalue){ 
     $this->_yummy = $newvalue; 
    } 

    public function find_yummy(){ 
     return "Look, a {$this->_yummy}!"; 
    } 
} 
class pantry extends kitchen{ 

    public function __construct(kitchen $kitchen){ 
     $this->_kitchen = $kitchen; 
    } 

    public function change_yummyInKitchen($newvalue){ 
     $closure = Closure::bind(
      function()use($newvalue){ 
       $this->change_yummy($newvalue); 
      }, 
      $this->_kitchen, 
      "kitchen" 
     ); 
     $closure(); 
    } 
    public function find_yummyInKitchen(){ 
     $closure = Closure::bind(
      function(){ 
       return $this->find_yummy(); 
      }, 
      $this->_kitchen, 
      "kitchen" 
     ); 
     return $closure(); 
    } 
} 

$kitchen = new kitchen; 
$pantry = new pantry($kitchen); 

print $pantry->find_yummy();   // prints "Look, a cake!" 
print $pantry->find_yummyInKitchen(); // prints "Look, a cake!" 

$pantry->change_yummy("pie"); 
print $pantry->find_yummy();   // prints "Look, a pie!" 
print $pantry->find_yummyInKitchen(); // prints "Look, a cake!" 

$pantry->change_yummyInKitchen("pie"); 
print $pantry->find_yummy();   // prints "Look, a pie!" 
print $pantry->find_yummyInKitchen(); // prints "Look, a pie!" 

Кроме того, перечитывая свой вопрос и комментарии, я думаю, вы можете не понимать, что означает «родитель». Это относится к определению класса, а не к конкретным объектам. В вашем примере кода Kitchen является Pantry «s родительского класса, но объекта$kit создать внутри Pantry класса не„родительский“вашего $p объекта.

Есть причина, по которой это так сложно и неудобно: все не должно работать таким образом. Я понимаю, что вы уже знаете, что это нарушает инкапсуляцию и т. Д., И поэтому я не буду пытаться говорить вам об этом по этим причинам. Но, помимо «лучшей практики», повторная работа над этой идеей будет проще и работать лучше с меньше ошибок.

+0

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

+0

Вы делаете это. Это точно _why_ вы никогда не видите значение «пирог». См. Правки выше. ** Также **, см. Ниже ответ @ Jack относительно метода 'change_treat' (я пропустил это). – traq

+0

Я знаю, что создание новой кухни, если FindFood означает, что я получу пирог и **, эта часть ошибочна **. То, что я прошу, есть, что я передаю для закрытия :: bind для привязки к экземпляру родительской кухни вместо экземпляра Pantry. – VanillaBean

Смежные вопросы