![]() |
Цепочка вызовов в PHP
У PHP не самая лучшая репутация среди языков программирования. Язык развивался постепенно с течением времени, и это видно. Но команда разработчиков PHP последовательно улучшает язык с каждым выпуском. PHP 7, в частности, добился больших успехов как в функциях, так и в производительности. Другие преимущества языка включают в себя хорошую документацию, отсутствие проблем с хостингом и значительное количество онлайн-ресурсов для обучения. И да, все крупнейшие CMS-платформы (Wordpress, Drupal, Joomla) основаны на PHP. Итак, для тех из нас, кто использует PHP и хочет писать красивый код, как этого можно достичь? Скептики могут утверждать, что это невозможно, но я не согласен. Фреймворки вроде Laravel (“фреймворк PHP для веб-мастеров”) уже доказали их ошибочность. Один из паттернов, который часто реализуют Laravel и другие уважаемые фреймворки PHP, - это цепочка методов. Вот пример того, о чем я говорю, API конструктора запросов Laravel: $users = DB::table('users') ->where('votes', '>', 100) ->orWhere('name', 'John') ->get();Этот синтаксис “цепочки” хорош тем, что позволяет разработчикам писать код, который делает одну вещь за раз выразительным и читаемым способом. В приведенном выше примере легко увидеть, что происходит:
Конкретный пример Чтобы проиллюстрировать, как работает цепочка методов, давайте рассмотрим в качестве примера операции с массивами. PHP имеет много полезных функций массива, таких как array_map, array_filter, usort и т. д. Предположим, что у нас есть массив имен героев мультфильма Симпсоны, и мы хотим применить следующие преобразования:
$characters = [ 'Maggie Simpson', 'Edna Krabappel', 'Marge Simpson', 'Lisa Simpson', 'Moe Szyslak', 'Waylon Smithers', 'Homer Simpson', 'Bart Simpson' ]; // Ищем полные имена, которые заканчиваются на Simpson // Отфильтруем элементы, которые не совпадают $simpsons = array_filter($characters, function ($character) { return preg_match('/^.+\sSimpson$/', $character); }); // Заменяем "Simpson" пустой строкой для каждого элемента $simpsons = array_map(function ($character) { return str_replace(' Simpson', '', $character); }, $simpsons); // Сортировка элементов с помощью PHP "strcasecmp" usort($simpsons, function ($a, $b) { return strcasecmp($a, $b); }); var_dump($simpsons); // ['Bart', 'Homer', 'Lisa', 'Maggie', 'Marge']Это дает нам правильный результат, но те, у кого острый глаз, могут заметить несколько деталей: array_filter принимает массив и обратный вызов, но array_map принимает обратный вызов и массив. Почему эти функции принимают аргументы в другом порядке? Операции фильтрации и сопоставления сохраняются в переменной $simpsons, но usort обращается к нашему массиву по ссылке. Почему такая непоследовательность? Это не очень хорошо выглядит, если честно. Для сравнения давайте посмотрим, как эта задача может быть решена в JavaScript: const simpsons = characters .filter(character => character.match(/^.+\sSimpson$/)) .map(character => character.replace(' Simpson', '')) .sort((a, b) => b < a) console.log(simpsons)Решение JavaScript гораздо более элегантно. Массивы - это тип объекта в JavaScript, и это позволяет связывать операции с массивами. Кроме того, gриведенный выше JavaScript использует функции стрелок для краткости. PHP еще не имеет функций стрелок, но они могут появиться у нас в ближайшее время! Цепочка методов на массивах встроена в JavaScript, но мы можем эмулировать это в PHP, написав свой собственный пользовательский класс. Создание класса с цепочкой вызовов Назовем это Коллекцией. Экземпляр этого класса может быть создан путем передачи массива в конструктор. class Collection { private $array; public function __construct($array) { $this->array = $array; } } $characters = new Collection([ 'Maggie Simpson', 'Edna Krabappel', 'Marge Simpson', 'Lisa Simpson', 'Moe Szyslak', 'Waylon Smithers', 'Homer Simpson', 'Bart Simpson' ]);Пока что класс делает не так уж много — он просто сохраняет массив, переданный как частное свойство. Давайте сосредоточимся на добавлении метода публичного фильтра. public function filter($callback) { $this->array = array_filter($this->array, $callback); return $this; }Вместо того чтобы передавать как массив, так и функцию обратного вызова в качестве аргументов, как раньше, теперь требуется только функция обратного вызова. После преобразования свойства массива экземпляра возвращается сам экземпляр. Это делает возможным цепочку методов. Далее давайте добавим методы map и sort: public function map($callback) { $this->array = array_map($callback, $this->array); return $this; } public function sort($callback) { usort($this->array, $callback); return $this; }Теперь наши методы готовы к цепочке, но нам нужен способ вернуть конечный результат в виде массива. Это похоже на то, как конструктор запросов Laravel использует get() для выполнения запроса после того, как он был создан с помощью условных выражений. public function execute() { return $this->array; }И мы можем, наконец, связать методы массива следующим образом! $characters = new Collection([ 'Maggie Simpson', 'Edna Krabappel', 'Marge Simpson', 'Lisa Simpson', 'Moe Szyslak', 'Waylon Smithers', 'Homer Simpson', 'Bart Simpson' ]); $simpsons = $characters ->filter(function ($character) { return preg_match('/^.+\sSimpson$/', $character); }) ->map(function ($character) { return str_replace(' Simpson', '', $character); }) ->sort(function ($a, $b) { return strcasecmp($a, $b); }) ->execute(); var_dump($simpsons); // ['Bart', 'Homer', 'Lisa', 'Maggie', 'Marge']Очень похоже на JavaScript! Проблемы с порядком аргументов и доступом к ссылкам все еще существуют под капотом, но наш класс коллекции обрабатывает это за кулисами. В результате получается код, который намного чище и читабельнее! Резюме PHP печально известен своей неряшливостью, но Laravel и другие фреймворки используют цепочки вызовов (методы (методов). Операции с массивами в PHP не цепочечны, как в JavaScript, но базовый класс утилит (например, наш класс коллекций!) может быть использован для эмуляции этого процесса и сохранения некоторых маленьких причуд PHP за занавесом. Примечание. Использование цепочки без различения только для некоторой субъективной выразительности следует рассматривать как явный антипаттерн. В бизнес-доменах такие шаблоны, как DDD, защищают неизменяемость, которая нарушается цепочкой, поскольку вы возвращаете измененный $this. ![]() Автор этого материала - я - Пахолков Юрий. Я оказываю услуги по написанию программ на языках Java, C++, C# (а также консультирую по ним) и созданию сайтов. Работаю с сайтами на CMS OpenCart, WordPress, ModX и самописными. Кроме этого, работаю напрямую с JavaScript, PHP, CSS, HTML - то есть могу доработать ваш сайт или помочь с веб-программированием. Пишите сюда. ![]() |
Мои услуги
|
© upread.ru 2013-2021 При перепечатке активная ссылка на сайт обязательна. |