2012-03-06 2 views
4

Мне нужно отладить сокет-соединение, которое мой PHP-интерфейс делает для бэкэнд-сервиса на другом хосте, и мне нужно сделать это как можно ближе к металлу, насколько это возможно. Я уже абстрагировал соединение на разных уровнях, что, среди прочего, дает мне возможность подключить stream filters к соединению. Поэтому проблему нужно очень легко решить: упакуйте фильтр потока в класс, который позволяет выполнять произвольные обратные вызовы, когда данные отправляются или принимаются, а затем, например, присоединяют их к нескольким файлам журнала.Регистрация фильтра потока для PHP?

Единственная проблема заключается в том, что мое (наивное?) Ожидание того, что должна быть некоторая такая реализация фильтра, плавающая в Интернете, кажется неправильной! Я не против писать фильтр самостоятельно, но, может быть, есть что-то доступное, что мне просто не удалось найти?

Для справки я сделал google много очевидных изменений в «php logging stream filter».

Update: Чтобы уточнить, что я ищу что-то, что позволит мне писать код нравственно эквивалентный этому:

$params = array(
    'onDataSent' => function($data) { echo "Sent: $data\n"; }, 
    'onDataReceived' => function($data) { echo "Received: $data\n"; }, 
); 

stream_filter_register('logging', 'HookableStreamFilter'); 
stream_filter_append($someStream, 'logging', STREAM_FILTER_ALL, $params); 
+0

не уверен, что я понимаю, что вы ищете, но будет ли http://php.net/manual/en/function.stream-notification-callback.php вариантом? Это позволит вам подключаться к определенным событиям потока. – Gordon

+1

@Gordon: Это не сократит его, потому что я заинтересован в получении фактических данных из потока, чтобы я мог его зарегистрировать. Даже если бы это было так, то, что я ищу, было бы тем, что функциональность упакована в класс с разумным API. Я сделаю редактирование, чтобы показать пример кода. – Jon

+0

Есть ли у вас определения интерфейса вашей абстракции? – hakre

ответ

1

Для потомков, вот что я закончил нагнетание. Фильтр сам по себе происходит от php_user_filter, который описан в документации для stream_filter_register:

class HookableFilter extends php_user_filter { 
    public function filter($in, $out, &$consumed, $closing) { 
     $data = ''; 

     while ($bucket = stream_bucket_make_writeable($in)) { 
      $consumed += $bucket->datalen; 
      $data .= $bucket->data; 
      stream_bucket_append($out, $bucket); 
     } 

     call_user_func($this->params, $data); 
     return PSFS_PASS_ON; 
    } 
} 

Обратите внимание, что я использую непосредственно $this->params в качестве обратного вызова, делая это действительно спартанские функция (есть причина, см. Ниже)

Регистрация фильтр с PHP:

stream_filter_register('generic.hookable', 'HookableFilter'); 

Прикрепление фильтра к потоку:

$callback = function($data) { /* log the data */ }; 
stream_filter_append($stream, 'generic.hookable', STREAM_FILTER_READ, $callback); 
stream_filter_append($stream, 'generic.hookable', STREAM_FILTER_WRITE, $callback); 

Важно: Насколько я мог видеть, если вы приложите фильтр оба канала дуплексного потока (например, один из них произведен с stream_socket_client) , чтобы ваш фильтр не знал, на каком канале он работает, когда он вызывается. Поэтому, если вам нужно различать входящие и исходящие данные по мере того, как я был, единственный вариант - присоединить фильтр отдельно к каждому каналу. Если вы это сделаете, вы также обязательно захотите предоставить другой обратный вызов для каждого канала (не то же самое, что сделано в упрощенном примере выше).