Комментарии 28
Спасибо!
У вас Eventable получился Пабликом Морозовым, скажем protected метод есть, напрямую его вызвать не дало бы, но вот так сработает. А все потому что вот эта ветка делает бяку:
if( method_exists($this, $name) )
call_user_func_array(array(&$this, $name), $args);
class Protect extends Eventable {
protected function foo() {
echo «Foo»;
}
}
$protect = new Protect();
$protect->foo();
if( method_exists($this, $name) )
call_user_func_array(array(&$this, $name), $args);
class Protect extends Eventable {
protected function foo() {
echo «Foo»;
}
}
$protect = new Protect();
$protect->foo();
Можно и так писать, но это совсем не OOP-style. Особенно публичное свойство onA, которое можно по-всякому менять снаружи, и которое является одновременно объектом, массивом и методом.
Чем не угодил паттерн в классической реализации (типа java.util.Observable в Java) с методами addObserver, deleteObserver и notifyObservers?
Чем не угодил паттерн в классической реализации (типа java.util.Observable в Java) с методами addObserver, deleteObserver и notifyObservers?
ниже я даже привел ссылку на SPL реализацию именно этого подхода…
является одновременно объектом, массивом и методом
В этом и заключается удобство данного подхода.
Коллбэками можно удобно управлять, используя логику работы с массивами (при желании, можно даже запускать определённый коллбэк, ну это если совсем приспичит), а запуск цепочки происходит так как, если бы это был простой метод. В коде это выглядит очень опрятно, без нагромождения монструозных конструкций.
Люблю минимализм :)
А вот я у себя в вики тоже подборку паттернов пополняю время от времени, если кому-то интересен не только Observer, то посмотреть текущий список можно здесь: wiki.summercode.com/projects/wiki/wiki/Design_Patterns
Чтобы избавится от костыля нужно использовать статику, но там появляется свой совсем маленький костыленок :) pastie.org/1232329
1) передача параметров по ссылке deprecated.
2) ArrayObject вы нашли, а 2 интерфейса рядом нет? ru.php.net/manual/en/spl.misc.php
3) __call не вызывается, если доступный метод существует [проверка if( method_exists($this, $name)) лишняя] и, вообще, что мешает использовать все тот же call_user_func?
2) ArrayObject вы нашли, а 2 интерфейса рядом нет? ru.php.net/manual/en/spl.misc.php
3) __call не вызывается, если доступный метод существует [проверка if( method_exists($this, $name)) лишняя] и, вообще, что мешает использовать все тот же call_user_func?
Добавлю ещё, что предоставленный автором метод усложняет понимание того, что должно было и происходит в коде. В сложных системах с множеством вызовов наступит полный капец.
Лично я реализовал-бы систему с помощью простого и ясного метода $this->onA->message('This is A', $txt).
Лично я реализовал-бы систему с помощью простого и ясного метода $this->onA->message('This is A', $txt).
1) Да, спасибо, я заметил это немного позднее, не успел поправить текст статьи.
2) Буду посмотреть
3) Это отличная новость! Я сам не сообразил проверить код на возможность подобного, но раз это есть, значит можно избежать вызова private!
2) Буду посмотреть
3) Это отличная новость! Я сам не сообразил проверить код на возможность подобного, но раз это есть, значит можно избежать вызова private!
__call не вызывается, если метод существует и он публичный: __call() is triggered when invoking inaccessible methods in an object context.
Вот тут хорошо все сделано и описано
components.symfony-project.org/event-dispatcher/documentation
components.symfony-project.org/event-dispatcher/documentation
Прочитав недавно нововведения PHP 5.3, я обратил внимание на несколько интересных особенностей, скомпоновав которые можно получить реализацию шаблона проектирования Observer, гораздо красивее, чем имеющиеся в pear и symfony
Кажется, автор статьи в курсе :)
Да, я видел этот и код и примеры-монстры. Своей реализацией я хотел всего лишь добиться избавления от лишних цепочек вызовов и попытаться сделать код более минималистичным, не потеряв в удобстве использования.
Боюсь, что для этого придётся применить костыль и я буду очень признателен, если кто-то предложит решение более красивое.
Просто вызовите __invoke() напрямую. Так сработает как с 'invokable' объектами, так и с анонимной функцией (которая на самом деле тоже объект).
<?php
class Event
{
public function __invoke()
{
var_dump(__METHOD__);
}
}
class a
{
public $onBB = null;
public function __construct()
{
$this->onBB = new Event;
}
public function q()
{
$this->onBB->__invoke();
}
}
$q = new a;
$q->q(); // string(15) "Event::__invoke"
$q->onBB = function() {
var_dump(__METHOD__);
};
$q->q(); // string(9) "{closure}"
Под костылём я имел ввиду запись вида $this->{$name}.
А вызов __invoke(); напрямую — это то, от чего я пытался уйти. С тем же успехом можно было бы писать fireEvent и эта реализация ничем не отличалась бы от сотен предложенных ранее. К тому же, разве вызов __invoke() напрямую позволит передать аргументы в функцию?
А вызов __invoke(); напрямую — это то, от чего я пытался уйти. С тем же успехом можно было бы писать fireEvent и эта реализация ничем не отличалась бы от сотен предложенных ранее. К тому же, разве вызов __invoke() напрямую позволит передать аргументы в функцию?
в пхп позволит
<?php function foo($a, $b) { $v = func_get_args(); for ($i=0;$i<func_num_args();$i++) echo $i,' ',$v[$i].PHP_EOL; } foo('sdf',4,'46',array(1,2,3));
С тем же успехом можно было бы писать fireEvent и эта реализация ничем не отличалась бы от сотен предложенных ранее.
тем не менее это проще костыля с еще одним магическим методом. Альтернатива — копировать во временную переменную:
<?
//....
public function something() {
$e = $this->onBB:
$e($arg1, $arg2);
}
//...
К сожалению, оператор () в PHP на выражениях не вызовешь.
а не будет ли еррора при func_get_args() в качестве аргумента для другой функции? :)
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Реализация паттерна Observer средствами PHP 5.3