Создание собственных PHP функций в Laravel проекте +4

В Laravel есть много отличных функций которые упрощают работу с массивами, путями, строками, маршрутами, и прочими вещами — например любимая функция dd().


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


Если вы новичок в Laravel или PHP давайте пройдемся по всему процессу создания собственных PHP функций которые будут автоматически подгружаться в Laravel'ом.


Создание файла с функциями в Laravel


Для начала вы должны включить функции в контекст вашего Laravel приложения. В зависимости от ваших предпочтений, вы можете организовать хранение ваших файлов с функциями там где вы хотите, вот несколько предложеных мест:


  • app/helpers.php
  • app/Http/helpers.php

Я предпочитаю хранить их так app/helpers.php в корне пространства имен приложения.


Автозагрузка


Для использования ваших функций, вам нужно загрузить их в рантайм (жизненный цикл приложения). В начале моей карьеры я часто видел этот код в начале файла:


require_once ROOT . '/helpers.php';

PHP функции не могут автоматически подгружаться. Однако, у нас есть более лучшее решение с использованием Composer нежели использование require или require_once.


Если вы создадите новый Laravel проект вы увидите параметры autoload и autoload-dev в файле composer.json:


"autoload": {
    "classmap": [
        "database/seeds",
        "database/factories"
    ],
    "psr-4": {
        "App\\": "app/"
    }
},
"autoload-dev": {
    "psr-4": {
        "Tests\\": "tests/"
    }
},

Если мы хотим добавить свой файл с функциями, то в Composer для этого есть параметр files (который состоит из массива путей к файлам) который вы можете определить внутри параметра autoload:


"autoload": {
    "files": [
        "app/helpers.php"
    ],
    "classmap": [
        "database/seeds",
        "database/factories"
    ],
    "psr-4": {
        "App\\": "app/"
    }
},

Когда вы добавили новый путь в параметр files, вам нужно обновить авто-загрузчик выполнив:


composer dump-autoload

Теперь при каждом запросе файл helpers.php будет подгружаться автоматически так как Laravel загружает Composer’овский авто-загрузчик в public/index.php:


require __DIR__.'/../vendor/autoload.php';

Определение функций


Определение функций задача не сложная, хотя есть несколько предостережений. Все функции в Laravel обернуты специальной проверкой которая исключает вероятность коллизий:


if (! function_exists('env')) {
    function env($key, $default = null) {
        // ...
    }
}

Хотя тут может быть подвох, потому что мы можем выполнить функцию в ситуации когда она уже была определена, до того как мы ее назначили.


Я предпочитаю использовать function_exists для проверки моих функций, но если вы назначаете функцию в контексте своего приложения, вы можете отказаться от function_exists для проверки.


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


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


Примеры функций


Мне всегда нравилось как в RoR (Ruby on Rails) сделаны функции для путей и ссылок если вы определили маршрут ресурса. К примеру, для ресурса photos будут добавлены функции new_photo_path, edit_photo_path, и т.д.


Когда я использую ресурсную маршрутизацию в Laravel, я добавляю несколько функций которые упрощают работу с марщрутами в шаблонах. В моей реализации я добавляю функции которым я передаю Eloquent модель и которые возвращают маршрут на ресурс, например:


create_route($model);
edit_route($model);
show_route($model);
destroy_route($model);

Здесь показано как вы можете определить функцию show_route в вашем файле app/helpers.php (другие будут похоже):


if (! function_exists('show_route')) {
    function show_route($model, $resource = null)
    {
        $resource = $resource ?? plural_from_model($model);

        return route("{$resource}.show", $model);
    }
}

if (! function_exists('plural_from_model')) {
    function plural_from_model($model)
    {
        $plural = Str::plural(class_basename($model));

        return Str::kebab($plural);
    }
}

Функция plural_from_model() это всего лишь код который помогает получить имя ресурса основываясь на соглашениях именования.


Например, тут мы получаем имя ресурса на основе модели:


$model = new App\LineItem;
plural_from_model($model);
=> line-items

plural_from_model(new App\User);
=> users

Используя эти соглашения вы можете определять маршруты для ресурсов в файле routes/web.php:


Route::resource('line-items', 'LineItemsController');
Route::resource('users', 'UsersController');

После этого в вашем шаблоне вы можете использовать функции так:


<a href="{{ show_route($lineItem) }}">
    {{ $lineItem->name }}
</a>

И на выходе вы получите такой HTML код:


<a href="http://localhost/line-items/1">
    Line Item #1
</a>

Пакеты


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


Вы будете использовать тотже подход для файла composer.json, определяя параметр files как массив ваших файлов с функциями.


Обязательно добавьте function_exists() в проверку вашей функции для того чтобы проект использующий ваш код не поломался из-за колизий имен.


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


Источник: https://laravel-news.com/creating-helpers

Вы можете помочь и перевести немного средств на развитие сайта



Комментарии (6):

  1. Samouvazhektra
    /#10559986

    На самом деле таким образом хелперы можно добавлять в любой проект под композером, хоть в Yii, хоть без фрейма, так что Laravel тут ни при чём.
    Но важно с ними не переборщить!

  2. VolCh
    /#10560176

    И неймспейсы для функций поддерживаются.

    А вот про приоритет загрузки было бы интересно узнать. Как, например, загрузить свою функцию гарантированно до ларавеловской, как бы переопределить её.

  3. Asikk
    /#10560778

    А почему не использовать класс-хелперы со статическими методами? Экономим несколько байт кода?

    • ZloAdmin
      /#10560794

      Я думаю потому что глобальные функции в шаблоне будут выглядеть лучше.

    • ellrion
      /#10560868

      такие функции за счет объявления с использованием function_exists можно перекрыть например временно для чего то. просто объявив свою такую функцию чуть раньше. Ну и плюс это типо ларавель вэй.

  4. Rpsl
    /#10560954

    browner12/helpers пакет который берет все подключение на себя, позволяет генерировать хелперы через artisan и подключать из через конфиг.