Как стать автором
Обновить

Комментарии 21

Спасибо за отклики! Будет больше — обязательно напишу про POST запросы и работу с куками.
Сбасибо за подробную руководству!
Мне нужна как раз работа с POSTом. Будем ждать следующих статьей.
Сделаю в ближайшие пару дней.
Сделайте пожалуйста подсветку кода.
Готово. Сразу не знал просто, как ее сделать…
Вот теперь красиво и читабельно!
Первый блин частенько комом бывает. Тем более когда не всё очевидно как делать. Впредь постараюсь сразу нормально выкладывать.
Браво — велосипед едет :) Потом обернете в класс. А вообще маленькая подсказочка как работать с неблокируемыми сокетами и не тратить времние на днс лукап и прочее.
Запускаете 100 неблокируемых коннектов в 2 процессах (т.е. тупо по писят) первый процесс собирает айпшники для доменов, второй коннектится собственно к доменам по айпи. В такой модели у вас никогда не будет простоя, даже если хост не найден (т.к. gethostbyname() пользуется вродебы системным таймаутом а на жестко задаваемый плевать хотел.)
Ну, по порядку.
Первое, в класс я лично оборачивать и не собираюсь — реальное применение этого кода значительно сложнее приведенного примера, и там не так просто (да и смысла нет) делать класс. Кто хочет, может, конечно, «обернуть».
Второе, пример сделан на cURL, а libcurl блокирующая (асинхронно только через обертку конкретного ЯП). Сам же PHP нити не поддерживает, насколько мне известно.
Третье, таймаут gethostbyname() задаётся socket_set_timeout(). По крайней мере так написано на php.net. ( Самы сокеты в PHP применял редко, обычно на асме их, так что на тонкостях таймаутов настаивать не могу. )
Четвертое, много доменов имеют очень большие временные задержки между отправкой запроса и приходом ответа. Иногда до 10-20 секунд. Соответственно, время затрачиваемое на DNS lookup роли вообще практически не играет.
Велосипед то он велосипед, но!
очень уж он часто востребованный велосипед. Слишком многим не хватает в php тридов…

PS: раньше писал на перл, потом присел на пхп для повседневных задач. в итоге когда столкнулся с подобной проблемой делал на пхп велосипед тоже, хотя знал что это можно сделать _правильнее_ на перл, но на пхп както проще и быстрее сделать… странно да?
Вот и я в Web начинал с Перла. А на PHP пересел лишь потому, что с ним больше охват поддерживаемых хостингов и выше спрос на задачи. Вот теперь в основном на нем для Web и пишу.

Посмотрим еще, как на продолжение отзывы будут. POST, управление печеньками и еще по мелочи…
Не хотел бы получить минусов, как это часто бывает на Хабре, ибо он не жалует какое-либо обучение, что расстраивает, но все же: Чем классы удобнее функций? Наверное легче воспользоваться одной функцией, просто передав в нее массив параметров, чем взять объемный класс, который даже непонятно как подключить, а ведь еще и использовать надо… А тем более, когда одну функцию умудряются обернуть в библиотеку :/
Разные задачи, разный подход, если что-то мелкое, то и функции достаточно, если долгоиграющий проект с постоянно поддержкой, лучше классами обходиться. Причин может быть много.

P.S.
Минусов не получишь, потому что статья 2009 года, в старых статьях минусы сложно получить.
Ах да, и правда, статья старая…

Согласен, при разработке крупных проектов, особенно которые будут поддерживаться разными программистами, классы оказываются очень удобными и подчас незаменимыми. Просто для всего свое применение. Вот я и ратую за то (особенно этим часто грешат начинающие программисты), когда их используют по сути не по назначению, и часто самому приходится упрощать его, удаляя все конструкторы и методы, и получая в итоге из увесистой библиотеки одну функцию. Ну максимум две) Вторая — служебная для каких-нибудь внутренних преобразований. Например, тут — наглядный пример того, что можно обойтись одной простой функцией.
Во многом вопрос привычки и единообразия стиля.
Вот прямо сейчас переписываю свой древний проект (времен пхп4) под новое окружение. Я как-то даже не задумывался — а зачем собственно я эти библиотеку в класс завернул?.. Сразу завернул и всё. Равно как не думал о том что более кошерно будет делать синглтон чем тупо всё статикой делать.
Сейчас задумался. Первое что приходит в голову — а как я ее подгружать буду? Жестко инклюдом? Добавлю эти функции в файлик шорткатсов где у меня лежат все функции? Писать какую-то автозагрузку для библиотек? Вне зависимости от того каким путем идти я потрачу на это больше времени чем завернув в класс — заворачивая в класс просто кодишь, не думая. Разве что я задумался о том куда класс ложить — в хелперы или компоненты. Ну ок, пойду я против течения сделаю таки функцией. И потом кто-то возьмет проект на поддержку вместо меня (а это одна из целей рефакторинга — отвязать поддержку от меня). Он потратит какое-то время чтобы найти эти функции. Нет умный ИДЕ конечно поможет. Но лично я обычно по старинке лезу в тот файл что ожидаю, а уж если не получилось то ищу или тыкаю «показать объявление» или что-то вроде… А так в принципе то класс и на класс не тянет — один публичный метод, два приватных (именно приватных, я не буду от этого класса наследоваться, я его полностью переписывать буду потом).

Ну а вообще да, мысль забавная. Бывает действительно берем старые библиотеки, делаем из них классы, налепляем синглтонов и прочего, а потом когда часто используем — делаем функции в шорткатсах которые вызывают наши классы)
Вставлю и свои 5 копеек, если можно.

В приведенном примере используется переменная "$ghandler", но она не объявлена. Ее следует заменить на $mh, тогда пример будет работать «из коробки».

И да, было бы круто, если бы вы это оформили в виде класса ;) и залили куда то на гитхаб какой то ;)

Спасибо за статью.
И еще… там где echo вставляются вот такие кавычки «» — они соответственно не поддерживаются в php :(
Было бы удобней если бы для echo использовались обычные одинарные или двойные.
Кавычки в оригинале и были «нормальными», это уже перемены на Хабре за эти годы привели к такому виду кода.
С $ghandler согласен, уже и не помню, почему он в примере встретился.

А насчет github… Этот код сейчас видится настолько простым и очевидным, что выкладывать его как-то не серьезно прямо. Даже с допилками, которые с ним происходили за несколько лет.
Попробовал в деле коробочную версию скрипта… ну почти хорошо. Если коллбек выполняется не мгновенно, то возникнут проблемы. Допустим у вас 10 страниц каждая парсится по 1 секунде (время выполнения коллбека), а мультикурл загружает все страницы за 3 секунды, тогда коробочный скрипт отпарсит лишь 3 страницы, Если хорошенько подумать, то можно понять почему. Главный цикл заканчивается, когда всё страницы загружены, но не факт, что все распарсены.

Чтобы этого избежать нужно вместо:
if ( $running != $prev_running ) {
    $info = curl_multi_info_read( $mh );
    ...
}

написать следующее:
do {
    $info = curl_multi_info_read( $mh );
    ...
} while ($info);

Переменную $prev_running удалить.
При запуске скрипт выдает ошибку. В коде походу все еще ошибка. Здесь
 $info = curl_multi_info_read( $ghandler );

вместо $ghandler должно быть $mh
Еще два момента.
Данный скрипт может пропускать заданные юрлы. Фишка в том, что curl_multi_info_read( $mh) возвращает последнее сообщение, но в очереди могут остаться еще сообщения.
Ну и насчет цикла без пауз до окончания загрузки всех страниц — это излишняя нагрузка на процессор.

Здесь my_callback надо обернуть в кавычки:

var_export( http_load( $urls, my_callback ) );

Нужно отключить проверку SSL-сертификата, иначе при чтении по https вываливается ошибка #60 SSL certificate problem: unable to get local issuer certificate

curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

Зарегистрируйтесь на Хабре , чтобы оставить комментарий

Публикации