За последние 24 часа нас посетили 22657 программистов и 1278 роботов. Сейчас ищут 806 программистов ...

Перекрытие функции-хелпера в Laravel

Тема в разделе "Решения, алгоритмы", создана пользователем artoodetoo, 15 апр 2021.

Метки:
  1. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.076
    Симпатии:
    1.237
    Адрес:
    там-сям
    Это не вопрос, а готовое решение. Предлагается к обсуждению.

    Laravel содержит множество вспомогательных функций-помошников. Например функция env() работает в конфигурационных файлах. Если вы загляните в файл с функцией (например в PHPStorm нажав Cmd кликните на её упоминание в коде), то увидите такое:
    PHP:
    1. if (! function_exists('env')) {
    2.  
    3.     function env($key, $default = null)
    4.     {
    5. ...
    То есть подразумевается, что функция может быть переопределена где-то. Если такая фнкция уже объявлена, то не пытаемся создать её заново (ибо это вызвало бы ошибку PHP).

    [offtopic]
    Зачем вообще может понадобиться перекрывать env(). Ну например, чтобы иметь возможность задавать данные своего кастомного типа. Например обрабатывать префикс в значении параметра "json:" или "enc:". В дефолтовом файле .env ты можешь увидеть префикс "base64:" , но увы, этот префикс отрабатывается для конкретного параметра а не для всех, какие могли бы понадобиться. А можно было бы...
    [/offtopic]

    Как описать свой вариант env()?
    Попытаемся сделать всё по науке: создаем свой файл app/Helpers/helpers.php, прописываем его в composer
    Код (Text):
    1.  
    2. "autoload": {
    3.     "files": [
    4.         "app/Helpers/helpers.php"
    5.     ],
    Наш собственный файл helpers.php
    PHP:
    1. function env($key, $default = null)
    2. {
    3. // . . .
    4.     if (Str::startsWith($value, 'base64:')) {
    5.         $value = base64_decode(substr($value, 7));
    6.     }
    7. // . . .
    8. }
    Получаем ошибку "функция уже определена". Потому что composer autoloader работает так: сначала он подгрузит автозагружаемые файлы из vendor, а только потом наш!

    Единственный выход, который я нашел, это явное подключение файла ДО стандартного автолоадера.
    У нас есть одна точка входа для веб-запросов public/index.php и одна точка входа для консольных команд artisan (без расширения, хотя это php файл). Придется вставить свой require в оба два файла.:

    artisan
    Код (Text):
    1.  
    2. // ...
    3. require __DIR__.'/app/Helpers/helpers.php';
    4. require __DIR__.'/vendor/autoload.php';
    Упоминание в composer.php нам больше не нужно.
    Можно ли изменять файлы index.php или artisan? А почему нет! Они не в vendor/, они часть вашего проекта и они не перезаписываются при composer install/update.

    Прошу коментировать.
     
    #1 artoodetoo, 15 апр 2021
    Последнее редактирование: 15 апр 2021
  2. ADSoft

    ADSoft Старожил

    С нами с:
    12 мар 2007
    Сообщения:
    3.824
    Симпатии:
    738
    Адрес:
    Татарстан
    наверное теоретически можно хелпер в своем пространстве имен заюзать... но вызывать правда потом тоже с неймспейсом типа my_coll_helper\env()
    ...
    еще можно rename_function или override_function

    нужно ли только все это?
     
  3. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.076
    Симпатии:
    1.237
    Адрес:
    там-сям
    нужно как элегантное решение некоторых задач. неэлегантно тоже можно.
    в том-то и дело, что свой неймспейс приводит к тому что надо изменять места обращения к хелперам. это именно то, чего я пытаюсь избежать.

    любые найденные ссылки на override_function ведут к 404
     
    don.bidon нравится это.
  4. Androbim

    Androbim Новичок

    С нами с:
    17 июн 2021
    Сообщения:
    49
    Симпатии:
    9
    Непринципиально, но, чтобы не "бросалось в глаза", я бы сделал как-то так.
    В index.php только что-то такое:
    Код (Text):
    1. <?php
    2.  
    3. (require __DIR__ . '/../config/bootstrap.php')->run();
    Повторяю, непринципиально, на суть не влияет.