Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: "Сигналы и слоты" в PHP, как в Qt  (Прочитано 7844 раз)
0 Пользователей и 1 Гость смотрят эту тему.
RuNTiME
Помогающий

ru
Offline Offline
Пол: Мужской

« : 24-10-2008 13:08 » 

Всех приветствую! Я недавно начал изучать замечательную библиотеку Qt. В этой библиотеке основополагающей технологией является технология "Сигналов и слотов", которая позволяет связывать объекты между собой, причем так, что они о друг друге ничего не знают. Сама идея просто уникальна и мне захотелось использовать её при программировании на PHP.
Хочется узнать ваши мнения об этой технологии и реализации её на PHP.
И за одним выкладываю код, который пока что удалось написать:
Код:
<?php
class CObject {
    private static 
$connections;
    private 
$class_id 0//уникальный идентификатор класса
    //функция подключения классов
    
public static function connect($emm_class$signal$dest_class$slot) {
        static 
$id 0//генератор уникальных идентификаторов классов
        
if(! $emm_class->class_id//если идентификатора нет,
            
$emm_class->class_id = ++$id//формируем новый
        
self::$connections[$emm_class->class_id][$signal][] = 
            array(
$dest_class$slot);
    }
    
//отправка сообщений
    
public function emmit($signal$params NULL) {
        
$conn = @self::$connections[$this->class_id][$signal];
        if(
$conn) {
            foreach(
$conn as $c) {
                eval(
"@\$c[0]->" $c[1] ."(\$params);");
            }
        }
    }
}

class 
CFoo1 extends CObject {
    
//функция - слот
    
public function slotOK() {
        echo 
"CFoo1::msgOK()<br>";
    }
}

class 
CFoo3 extends CObject {
    
//функция - слот
    
public function slotOK($param) {
        print(
"CFoo3::dump_var:<br>");
        print(
var_dump(nl2br(var_dump($param))));
        print(
"<br>");
        echo 
"CFoo3::msgOK()<br>";
    }
    public function 
slotHelloWorld() {
        echo 
"Hello, World!";
    }

}

class 
CFoo2 extends CObject {
    public function 
__construct() {
    }
    public function 
test() {
        
$obj->m_1 1;
        
$obj->m_2 = &#39;Hello, World!&#39;;
        //отправка сообщений
        
$this->emmit(&#39;signOK&#39;,$obj);
    
}
}

$a = new CFoo1();
$c = new CFoo3();
$b = new CFoo2();

CObject::connect($b, &#39;signOK&#39;, $a, &#39;slotOK&#39;);
CObject::connect($b, &#39;signOK&#39;, $c, &#39;slotOK&#39;);
CObject::connect($b, &#39;signOK&#39;, $c, &#39;slotHelloWorld&#39;);

$b->test();

?>

Программа выводит в браузер следующее:
Код:
CFoo1::msgOK()
CFoo3::dump_var:
object(stdClass)#4 (2) { ["m_1"]=> int(1) ["m_2"]=> string(13) "Hello, World!" } string(0) ""
CFoo3::msgOK()
Hello, World!
Записан

Любимая игрушка - debugger ...
Chuda
Гость
« Ответ #1 : 24-10-2008 13:15 » 

какая интересная идея Улыбаюсь
Записан
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #2 : 26-10-2008 15:40 » 

Такой вариант:

Код: (PHP)
<?php

/* Класс, реализующий механизм callback. */
class base
{
    var $_callback;

    function __constructor()
    {
        $this->_callback = array();
    }

    function add_callback($name, $cb)
    {
        if (!is_callable($cb))
            return false; /* лучше возбудить исключение или die */

        if (!isset($this->_callback[$name]))
            $this->_callback[$name] = array();

        $this->_callback[$name][] = $cb;

        return true;
    }

    function rm_callback($name, $cb)
    {
        if (!is_callable($cb) or !isset($this->_callback[$name]))
            return false; /* лучше возбудить исключение или die */

        foreach ($this->_callback[$name] as $key => $cb2)
            if ($cb == $cb2)
            {
                unset ($this->_callback[$name][$key]);

                return true;
            }

        return false;
    }

    function _do_callback($name, $params)
    {
        if (!isset($this->_callback[$name]))
            return;

        foreach ($this->_callback[$name] as $cb)
            if (is_callable($cb))
                call_user_func($cb, $params);
    }
}


/* Классы, поддерживающие callback из класса base. */
class A extends base
{
    function event($str)
    {
        $params = arra('str' => $str);
        $this->do_callback('event', $params);
    }
}

class B extends base /* не обязательно */
{
    function output($params)
    {
        echo $params['str'];
    }
}

/* Тест */

$a = new A;
$b = new B;

$a->add_callback('event', array(&b, 'output'));

$a->event('start');

$a->rm_callback('event', array(&b, 'output'));

$a->event('end');

/* Второй вызов event не приведет к выводу строки. */

?>

Существенный недостаток eval() - невозможность кеширования предкомпиленного кода.
« Последнее редактирование: 26-10-2008 15:45 от RXL » Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
RuNTiME
Помогающий

ru
Offline Offline
Пол: Мужской

« Ответ #3 : 27-10-2008 06:51 » 

RXL,  Спасибо, ИМХО не знал про функцию call_user_func. Сам думал, как избавится от eval ... ( eval is evil ) .  Улыбаюсь
Записан

Любимая игрушка - debugger ...
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #4 : 27-10-2008 08:14 » new

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

'func'
array('class', 'method')
array(&obj_ref, 'method')
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines