За последние 24 часа нас посетили 22102 программиста и 1057 роботов. Сейчас ищут 712 программистов ...

Правильно ли поступаю?

Тема в разделе "Прочие вопросы по PHP", создана пользователем Вероломство, 17 ноя 2021.

  1. Вероломство

    Вероломство Активный пользователь

    С нами с:
    19 июн 2017
    Сообщения:
    615
    Симпатии:
    24
    Роуты формируются примерно так (тупо пример, чтобы все варики затестить):

    PHP:
    1. return fn(Application $application) => $application->getRouter()
    2.     ->addGetRoute('/', fn() => [new HomeController(), '__invoke'])
    3.     ->addGetRoute('/test', [new HomeController(), '__invoke'])
    4.     ->addGetRoute('/{id}', [HomeController::class, '__invoke'], [
    5.         'id' => '\d+'
    6.     ])
    7.     ->addGetRoute('/{name}', HomeController::class);
    Резольвер:

    PHP:
    1. public function resolve(Request $request): void
    2. {
    3.     $result = $this->match($request);
    4.  
    5.     if (is_null($result)) {
    6.         // 404
    7.     } else {
    8.         $handler = $result['handler'];
    9.         $arguments = $result['arguments'];
    10.  
    11.         if ($handler instanceof Closure) {
    12.             call_user_func($handler(), $request, $arguments);
    13.         } elseif (is_callable($handler)) {
    14.             call_user_func($handler, $request, $arguments);
    15.         } elseif (is_array($handler)) {
    16.             [$controller, $action] = $handler;
    17.             call_user_func([new $controller, $action], $request, $arguments);
    18.         } else {
    19.             $route = new $handler;
    20.             $route($request, $arguments);
    21.         }
    22.     }
    23. }
    Как бы всё работает, всё нормально у меня (я по поводу проверок в резольвере)? :)
     
  2. artoodetoo

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

    С нами с:
    11 июн 2010
    Сообщения:
    11.072
    Симпатии:
    1.237
    Адрес:
    там-сям
    Тут такое дело, сколько бы ты вариантов указания экшн не реализовал, это и будут "все варики" твоего фреймворка. Хоть 1, хоть 10.
    Кстати, разве instanceof Closure не является частным случаем is_callable()? Помоему, одну проверку можно убрать, но я не проверял.
    --- Добавлено ---
    Из примера непонятно зачем само определение маршрутов оформлено в кложу.
     
  3. MouseZver

    MouseZver Суперстар

    С нами с:
    1 апр 2013
    Сообщения:
    7.751
    Симпатии:
    1.322
    Адрес:
    Лень
    Нет. Я так столкивался с проблемой одной.


    PHP:
    1. <?php
    2.  
    3. class Foo
    4. {
    5.     public function __invoke()
    6.     {
    7.         return 2;
    8.     }
    9. }
    10.  
    11. $o = new Foo;
    12.  
    13. var_dump ( is_callable ( $o ), $o instanceof Closure );

    bool(true)
    bool(false)
    --- Добавлено ---
    @Вероломство, ты компосером владеешь ?
     
  4. artoodetoo

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

    С нами с:
    11 июн 2010
    Сообщения:
    11.072
    Симпатии:
    1.237
    Адрес:
    там-сям
    Closure это анонимная функция и она является callable. И в call_user_func() её тоже можно вставлять как другие callable.

    Создам кложу для проверки четности, например.

    Код (Text):
    1.  
    2. $ tinker
    3. Psy Shell v0.9.12 (PHP 7.4.25 — cli) by Justin Hileman
    4. >>> $closure = fn($x) => $x % 2 == 0;
    5. => Closure($x) {#4735 …2}
    6. >>> var_dump ( is_callable ( $closure ), $closure instanceof Closure );
    7. bool(true)
    8. bool(true)
    9. => null
    10. >>> call_user_func($closure, 1)
    11. => false
    12. >>> call_user_func($closure, 2)
    13. => true
    14. >>>
    @Вероломство получается if ($handler instanceof Closure) можно убрать, потому что следующий if всё что надо сделает для варианта с Closure
     
    #4 artoodetoo, 17 ноя 2021
    Последнее редактирование: 17 ноя 2021
  5. Вероломство

    Вероломство Активный пользователь

    С нами с:
    19 июн 2017
    Сообщения:
    615
    Симпатии:
    24
    @artoodetoo мне чтобы callable запустить, то нужно просто $handler прописать, но чтобы анонимку запустить (в которой содержится callable), то нужно получить доступ к её содержимому, а это $handler() :(

    поэтому и идёт проверка именно на Closure
     
  6. artoodetoo

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

    С нами с:
    11 июн 2010
    Сообщения:
    11.072
    Симпатии:
    1.237
    Адрес:
    там-сям
    Я нифига не понял, но дело хозяйское :) зачем такое может понадобиться, кроме как для абстрактного бессмысленного примера...
     
  7. Вероломство

    Вероломство Активный пользователь

    С нами с:
    19 июн 2017
    Сообщения:
    615
    Симпатии:
    24
    ну так зачем ты тогда предлагаешь бессмысленный пример?

    ты предложил не проверять на анонимку, НО вызывать, как callable в обоих случаях, в то время как анонимка - это не callable - это анонимка, в которую запакована callable )))

    чтобы получить callable из анонимки, то её нужно вызывать со скобками, как функцию, дядя )))

    PHP:
    1. call_user_func($handler() /** Closure */, $request, $arguments);
    2.  
    3. call_user_func($handler /** callable */, $request, $arguments);
     
  8. artoodetoo

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

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

    вопрос зачем оно там запаковано? :)

    есть осмысленный пример анонимной функции в описании маршрута: то что из коробки показано в laravel. типа такого
    тут ничего не "запаковано". просто побыстрому создали эшен без ссылки на контроллер.
    PHP:
    1. Route::get('/', function () {
    2.      return view('welcome');
    3. });
    видишь разницу со своей задумкой? вот про решение для такого примера я тебе написал "проверять на Closure специально не нужно. оно будет выполняться и без этого".
    --- Добавлено ---
    также непонятно зачем ты "запаковал" саму таблицу маршрутов в анонимную функцию. чтобы где-то придумать как его "распаковать"? )))
     
  9. Вероломство

    Вероломство Активный пользователь

    С нами с:
    19 июн 2017
    Сообщения:
    615
    Симпатии:
    24
    таблица маршрутов не запакована в анонимку, а сделано это для того, чтобы автокомплит шторма работал у $application СРАЗУ, потому что маршруты в инклудном файле находятся, а phpdoc не прикалывает писать для $application)))

    в анонимку запаковывается обработчик какого-то маршрута, если он callable и объект создаётся в момент вызова анонимки, в отличие от случая, когда обработчик уже callable и объект болтается уже готовый в таблице маршрутов

    PHP:
    1. ->addGetRoute('/', fn() => [new HomeController(), 'indexAction']) // объект будет создан при вызове анонимки
    2. ->addGetRoute('/test', [new HomeController(), 'indexAction']) // объект уже создан
    дядя Йода)))
     
    #9 Вероломство, 23 ноя 2021
    Последнее редактирование: 23 ноя 2021
  10. artoodetoo

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

    С нами с:
    11 июн 2010
    Сообщения:
    11.072
    Симпатии:
    1.237
    Адрес:
    там-сям
    Лол. Ты смешной.

    Вопрос был: зачем? А ты взялся рассказывать как работает функция. Зачем добавлять что-то ненужное и при этом делать невозможным экшен без класса контроллера?
     
  11. Вероломство

    Вероломство Активный пользователь

    С нами с:
    19 июн 2017
    Сообщения:
    615
    Симпатии:
    24
    экшен без класса, метод ты запускаешь без экземпляра или что?
     
  12. artoodetoo

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

    С нами с:
    11 июн 2010
    Сообщения:
    11.072
    Симпатии:
    1.237
    Адрес:
    там-сям
  13. artoodetoo

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

    С нами с:
    11 июн 2010
    Сообщения:
    11.072
    Симпатии:
    1.237
    Адрес:
    там-сям
    Моё предложение — поддерживай такие варианты:

    • [HomeController::class, 'getIndex']
    • 'HomeController@getIndex' // то же, что и предыдущий, только выглядит короче
    • HomeController::class // подразумевыается что будет создан объект класса и у него вызовется __invoke()
    • fn() => 'Hello world!' // на самом деле ЛЮБОЙ callable, а не только кложа. результат выполнения это непосредственно нужное действие (экшн), а не ссылка на что-то-там.
    --- Добавлено ---
    ты знаешь как всё это сделать.
    --- Добавлено ---
    мне кажется ты просто запутался в том что является callable и как используется магия __invoke.
     
  14. Вероломство

    Вероломство Активный пользователь

    С нами с:
    19 июн 2017
    Сообщения:
    615
    Симпатии:
    24
    __invoke тут не при чём - просто я чтобы не создавать ДЛЯ ПРИМЕРА 4 разных контроллера, то использовал один для всех вариантов, поэтому там __invoke отсвечивает, чтобы в свою очередь отработал И варик с магией ПРИ ДЕБАГЕ моём своего рода :)

    я с тобой соглашусь, что нужно убирать всю эту дичь, НО я вообще отказался от Closure и callable, оставил только [HomeController::class,'__invoke'] и просто HomeController::class (зачем мне запакованные или готовые объекты в роутах), я обработаю строковые значения и будет так:

    PHP:
    1. class Resolver
    2. {
    3.     private Container $container;
    4.  
    5.     public function __construct(Container $container)
    6.     {
    7.         $this->container = $container;
    8.     }
    9.  
    10.     public function resolve(string|array $handler): callable
    11.     {
    12.         if (is_string($handler)) {
    13.             return $this->container->get($handler);
    14.         }
    15.  
    16.         [$controller, $action] = $handler;
    17.  
    18.         $controller = $this->container->get($controller);
    19.  
    20.         return [$controller, $action];
    21.     }
    22. }