Обновить
52
Лисаченко Александр@NightTiger

Пользователь

22
Подписчики
Отправить сообщение
Имхо, тестирование не при чем. Достаточно соблюдать правило Деметры. То есть, объект должен вызывать методы максимум на один уровень ниже (либо свои собственные методы, либо методы у своих прямых зависимостей):

class Test
{
    function goodMethod() {
        $this->dependency->method1();
        $this->another->method2();
    }

    function badMethodInTheClass() {
        $this->dependency->anotherMethod()->method3(); // Very bad!
    }
}


Соблюдая это простое правило, всегда можно любому классу подсунуть нужные моки и протестировать независимо от всего остального кода. DI-контейнеры немного помогают соблюдать это правило, собирая зависимости в один уровень.
Затем, что эта штука применяется в Symfony2 и ZF2 для реализации Lazy-сервисов в контейнере. И производительность должна быть очень хорошей, иначе профита было бы мало в случае массового применения в приложении.
Кхм, эта статья — результат моего обсуждения на гитхабе с Marco и Matthieu )) Но, пожалуйста, сделайте правки в тексте: Marco — это он, а то как-то неудобно даже это видеть.
Имхо, самый большой недостаток-это ругань IDE на этот сахар. Не имея нормальной поддержки для этих конструкций на уровне IDE, сама разработка уже не покажется сахаром.
Эх, подлил я масла в огонь со своими фильтрами )
Однако приятно, что мои слова помогли изучить такую интересную технику. Реализация получилась весьма интересная, однако надо учесть много факторов, таких как опкод-кэшеры, корректную работу со стримами и прочее. А то в реальном применении все свалится благополучно, потому что код будет закэширован опкод-кэшером.
Если интересно посмотреть на динамические примеси, то это технология называется Introduction в мире AOP:

Introduction: declaring additional methods or fields on behalf of a type. AOP allows you to introduce new interfaces (and a corresponding implementation) to any advised object. For example, you could use an introduction to make a class implement an IsModified interface, to simplify caching. (An introduction is known as an inter-type declaration in the AspectJ community.)


Эта фишка уже поддерживается в моем АОП-фреймворке для PHP. Если вкратце — она дает возможность к любому классу добавить «на лету» интерфейсы и трейты без изменения исходного кода класса. Если интересно — небольшой материал есть тут: Aspect-Oriented Pointcuts and Advices (последний параграф)
Есть данные с прошлой версии фреймворка на слабенькой машинке: performance test. Этот тест показывает, что 10000 итераций пустого метода выполняются за 3.0мс, тогда как с дополнительным советом в моей библиотеке — за 90мс. Если делать аналогичное с помощью экстеншена PHP-AOP, то получится за 25мс. Однако, скорость экстеншена очень сильно падает с ростом количества советов (обратите внимание, как начинает тормозить экстеншен, в случае если есть много срезов, которые не совпадают с измеряемым методом)
Тем не менее, это синтетический тест, потому что, как правило, сам метод работает в реальных условиях медленнее совета, вызывается всего раз или два и замедление скорости от совета практически незаметно из-за значительной оптимизации. Таким образом, добавление совета к большому методу почти не тормозит его работу и если этот метод вызывается один или несколько раз, то его даже не будет заметно.
Я бы назвал все это аспектно-ориентированным программированием ) То, что вы делаете с помощью парсера очень походит на то, что делает моя либа, написанная на PHP. Я скоро планирую завершить работы и по перехвату стандартных функций, типа fopen, mysqli_open и др. Основное отличие-работать будет везде, на любом хостинге.
Всех интересующихся приглашаю на DevConf )
Все это очень странно, но у меня Windows8 во всех (!) браузерах разрывает коннект при запросе этого ресурса
Скриншоты

коммент товарища Groove выглядит так:
На соседнем компе у товарища все хорошо. Проверил у себя фаервол-чистый, логи антивируса-тоже, прочие картинки и капчи в инете отображаются…
Мне кажется, или капча сломана и голосовать не получится?
Да, там есть несколько мест, которые приводили меня в полный ступор, потому что не было возможности двинуться дальше из-за всяких ограничений языка. Два года потребовалось на то, чтобы решить этот большой ребус, но я рад, что у меня все получилось и я могу показать ее сообществу.
Надеюсь, она найдет свое место в приложениях, потому что область применения широка: контрактное программирование, логирование, кэширование, новые шаблоны программирования, новые подходы к разработке ПО.
Это будет позже, вся теория и практические наброски у меня готовы. Можно будет перехватывать даже простые функции, например file_get_contens, mysqli_open и т.д. Но только если они будут использоваться в неймспейсе, а не в глобальном пространстве.
А этот вариант не подошел: «Статья понравилась, возьму на заметку, но пока не время для АОП, остановлюсь на ООП.»?
нет, не сможете, это под силу только расширению, такому как runkit, либо PHP-AOP. Тот код, который уже загружен в память, невозможно изменить со стороны PHP. Но вот если вы перед этим подключите АОП, а потом уже передадите управление на superlib.php, то методы в классах уже можно будет перехватить.
Как говорят: «копейка — рубль бережет». Так и здесь, в коде одного метода — да, всего одна строчка, в коде класса их может быть уже пара десятков, а в коде всего приложения — несколько тысяч.
А еще интереснее будет, если у вас уже есть эти несколько тысяч сеттеров по всему проекту и у вас есть необходимость сделать их цепочечными, чтобы было удобно работать.
ок, уточнение: я перехватываю именно require/include и как частный случай, получается, перехватываю autoload, потому что где-то в нем тоже есть include/require. Сама функция include/require для меня недосягаема, но вот путь к подключаемому файлу я изменить могу, что моя библиотека и делает.
Это концепция маркеров, вы с ней не сталкивались ранее? Когда, например, класс исключения помечают дополнительно такими маркерами, а потом ловят по классу интерфейса-маркера.

class AppException extends Exception implements ServiceLayerException
{
}

// ...

try {
    throw new AppException();
} catch (ServiceLayerException $e) {
    // .. service layer fault
}
Не обязательно вам писать аннотацию с @return, ее может вставить сама библиотека АОП, а IDE ее подхватит сама. Насчет магии — это ваш выбор, использовать или нет. Статья имеет исключительно ознакомительный характер, но ваши мысли и опасения мне понятны.

Не всегда сеттеры находятся в моделях. И не всегда они ваши и находятся на уровне приложения. Очень часто я встречаю код, где нужно настроить вендорский сервис, а в нем есть лишь тонна сеттеров и нет цепочечного интерфейса.
Все очень просто (если у вас phpStorm): зайдите в нужный вам класс и на самом классе нажмите Ctrl+H. Я думал, что этот инструмент всем знаком. )
Реализуется АОП в PHP ручками )
В самом PHP это пока не планируется, хотя для версии 4.0 были попытки, я даже где-то видел грамматику лексера PHP с учетом аспектов, но это уже в прошлом. Из нового — есть PECL-расширение PHP-AOP, которое разрабатывается, но там куча багов, сегфолтов, да и скорость в отдельных случаях меньше, чем у моей PHP-библиотеки. Моя же библиотека написана на чистом PHP и не требует никаких дополнительных экзотических расширений, за счет этого она стабильна и активно развивается.
Идея работы такая — отслеживаем момент загрузки любого PHP-кода (перехватываются incude/require), делаем статический анализ кода, вносим в него необходимые правки, создаем декоратор, подменяем им оригинальный класс и сохраняем в кэше, дальше отдаем этот код парсеру PHP. После таких манипуляций в памяти PHP будет находиться класс, уже имеющий расширенную функциональность, но с прежним именем класса.
Это краткий обзор предыдущих серий Санта-Барбары под названием «как сделать АОП»

Информация

В рейтинге
Не участвует
Откуда
Москва, Москва и Московская обл., Россия
Дата рождения
Зарегистрирован
Активность