У PHP плохая репутация из-за уродства. Но, язык развивается постепенно, и это видно.

Но у него также есть много хороших качеств. Команда разработчиков PHP последовательно улучшала язык с каждым выпуском. PHP 7, в частности, добился больших успехов как в возможностях, так и в производительности.
Читайте также: Эволюция PHP — v5.6 до v8.0

Другие преимущества языка включают в себя удобную документацию, вездесущий хостинг и значительное количество онлайн-ресурсов, которые можно использовать (в StackOverflow и других).

И да, все крупнейшие платформы CMS (WordPress, Drupal, Joomla) основаны на PHP, и в этой области предстоит проделать большую работу.

Итак, как это можно сделать для тех из нас, кто использует PHP и хочет писать красивый код

Скептики могут утверждать, что это невозможно, но я не согласен. Такие фреймворки, как Laravel (Читайте также: 10 популярных фреймворков PHP в 2020 году) уже доказали, что они не правы.

Одна из схем, которую часто используют Laravel и другие известные PHP-фреймворки, — это цепочка методов. (method chaining)

Вот пример того, о чем я говорю: Конструктор запросов Laravel

$users = DB::table('users')
    ->where('votes', '>', 100)
    ->orWhere('name', 'John')
    ->get();

Этот «цепочечный» синтаксис хорош тем, что позволяет разработчикам писать код, который делает одну вещь за один раз выразительным и читабельным способом. В приведенном выше примере легко увидеть, что происходит:

  • Посмотрит на строки в таблице users
  • Где голосов больше 100.
  • Или где имя пользователя Джон.
  • Получите результаты.

Конкретный пример

Чтобы показать, как работает цепочка методов, давайте рассмотрим операции с массивами в качестве примера. В PHP есть много полезных функций массива, таких как array_map, array_filter, usort и т.д., Но выполнение нескольких операций над одним массивом может стать проблемой.

Допустим, у нас есть массив имен Симпсонов, и мы хотим применить следующие преобразования:

  • Отфильтровать все имена, которые не заканчиваются на «Симпсон».
  • Сопоставить каждое полное имя только с именем. Например, мы заменили бы «Лиза Симпсон» просто «Лиза».
  • Сортировать наши результаты в алфавитном порядке.

Вот один из способов решения нашей проблемы:

$characters = [
    'Maggie Simpson',
    'Edna Krabappel',
    'Marge Simpson',
    'Lisa Simpson',
    'Moe Szyslak',
    'Waylon Smithers',
    'Homer Simpson',
    'Bart Simpson'
];
// полные имена, которые заканчиваются на Симпсон
// Отфильтровать элементы, которые не соответствуют
$simpsons = array_filter($characters, function ($character) {
    return preg_match('/^.+\sSimpson$/', $character);
});
// Замените «Симпсон» пустой строкой для каждого элемента
$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']

Это дает нам правильный результат, но те, у кого острый взгляд, могут заметить несколько деталей:

  1. array_filter принимает array и callback, но array_map принимает callback и array. Почему эти функции принимают аргументы в другом порядке?
  2. array_filter и array_map сохраняются в переменную $simpsons, но usort обращается к нашему массиву по ссылке. Почему несоответствие?
  3. Это выглядит некрасиво.

Для сравнения давайте посмотрим, как можно решить эту проблему в JavaScript:

const simpsons = characters
  .filter(character => character.match(/^.+\sSimpson$/))
  .map(character => character.replace(' Simpson', ''))
  .sort((a, b) => b < a)

console.log(simpsons)

Решение JavaScript намного элегантнее. Массивы являются типом объектов в JavaScript, и это позволяет объединять операции с массивами.

JavaScript выше использует функции стрелок для краткости. В PHP пока нет функций стрелок, но они могут появиться в ближайшее время!

Цепочка методов для массивов встроена в JavaScript, но мы можем эмулировать это в PHP, написав собственный класс.

Создание класса с цепочечными методами

Давайте назовем это Collection. Instance этого класса можно создать, передав массив в конструктор.

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;
}

Вместо того, чтобы передавать оба массива и callback функцию как аргумент, как раньше, теперь требуется только callback функцию

После преобразования свойства массива instance возвращается сам instance. Из-за этого мы можем использовать метод цепочки.

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;
}

Собирая все это вместе, наш класс выглядит так:

class Collection
{
    private $array;
    public function __construct($array)
    {
        $this->array = $array;
    }
    public function filter($callback)
    {
        $this->array = array_filter($this->array, $callback);
        return $this;
    }
    public function map($callback)
    {
        $this->array = array_map($callback, $this->array);
        return $this;
    }
    public function sort($callback)
    {
        usort($this->array, $callback);
        return $this;
    }
    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']

Проблемы с порядком аргументов и доступом к ссылкам все еще существуют под капотом, но наш класс Collection обрабатывает это за сценой. В результате получается код, который намного чище и читабельнее.

PHP

About the Author

Ergashev Lazizbek

Добрый день, дорогие мои читатели, позвольте мне рассказать вам немного о себе. Я Лазизбек Эргашев, я веб-разработчик из Узбекистана. В основном я использую laravel/php для бэкэнда и vuejs/javascript для фронтэнда. Основная цель моего блога - поделиться с вами своим опытом и знаниями.

View All Articles