Ответы пользователя по тегу PHP
  • Почему Service Locator это зло и что использовать вместо?

    kraso4niy
    @kraso4niy
    fullstack
    1. Вы всё верно поняли. Сложность в том что внутри может оказаться не та структура которую вы ожидайте (ожидалась)

    Но это не значит что это плохо. Эту проблему можно решить валидацией. В вашем примере достаточно проверять на instanceOf. Тогда код станет правильный. А в symfony сделали это ещё лучше и добавили строгость к типам для сервис локатора через подписку на сервисы.

    Что бы понять когда применять сервис локатор, а когда инъекцию пройдите по ссылке https://symfony.com/doc/current/service_container/... и почитайте.

    Там есть пояснение:
    Sometimes, a service needs access to several other services without being sure that all of them will actually be used. In those cases, you may want the instantiation of the services to be lazy. However, that’s not possible using the explicit dependency injection since services are not all meant to be lazy


    Можно пояснить на примере: допустим у вас есть класс с методом, и внутри метода только в некоторых случаях вам понадобится сделать запись в БД (допустим обращение к сервису в виде get->('db')).

    Например:
    if($userData = $request->get('user_data')) {
        $db = $serviceLocator->get('db')->insert($userData);
    } else {
       die("user data empty");
    }


    Если делать через инъекцию, то $db всегда будет инициализирована, например если проводить инъекцию через конструктор или метод, то объект вашего класса всегда будет при любых условиях запускать код инициализации $db и тратить на это ресурсы. Пример через инъекцию (тут тип инъекции через аргумент метода, аналогично можно сделать через конструктор или сеттер)

    class MyClass {
       // $db будет инициализрован, но используется только в 1 случае для if
      // если $db тяжёлый сервис и инициализируется долго это проблема!
       function httpResponse(Request $request, Database $db) {
          
           if($userData = $request->get('user_data')) {
              $db->insert($userData);
           } else {
              die("user data empty");
           }
       }
    }


    А в случае сервис локатора $db будет инициализирован только в условии когда придёт user_data. Таким образом если у вас контроллер использует 15 сервисов (но это bad code!), а одновременно нужен только 1 из них, лучше использовать сервис локатор.

    class MyClass {
       // В таком случае рекомендуется воспользоваться сервис локатором! 
       function httpResponse(Request $request, Database $db, Servive1 $s1, Service2 $s2) {
          
           if($userData = $request->get('user_data')) {
              $db->insert($userData);
              if ($db->lastId()) {
                   $s1->makeSuccess();
                   if($s1->isSuccess()) {
                       $s2->commit();
                   }
              }
           } else {
              $s2->rollback();
              die("user data empty");
           }
       }
    }


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

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

    P.S:
    Использовать service locator можно и в этом нет ничего страшного, особенно когда есть понимание что это такое и для чего он нужен.
    Ответ написан
    Комментировать
  • RabbitMQ: Растет количество каналов. Как правильно закрывать каналы?

    kraso4niy
    @kraso4niy
    fullstack
    Возможно там где у вас // тут полезная нагрузка скрипт долго работает и держит открытый channel. Далее запускается еще один такой же и также долго работает... и так много раз, следовательно tcp забивается , cpu растет и все падает.
    Можно переписать код , так чтобы после get перед полезной нагрузки канал закрывался. И еще не ясно зачем вам while. Получили одно сообщение и закрыли все все.
    Ответ написан
    Комментировать
  • Doctrine2 и кастомные поля

    kraso4niy
    @kraso4niy
    fullstack
    Сделайте сущность(entity) где будут храниться разные поля. В этой сущности будут хранится: тип поля, название, значения и ссылка(привязка) на сущность к которой это поле привязано. Привязку можно забить строго через yml или анотации, или же написать свой метод/класс для этого.
    Ответ написан
    Комментировать
  • Где можно найти примеры тестовых заданий на должность Php senior developer?

    kraso4niy
    @kraso4niy
    fullstack
    Вот вам тестовое задание от компании тикетлэнд.

    // Тестовое задание
    
    // Реализовать класс дерева, наследующийся от абстрактного Tree:
    
    class Node
    
    {
    
    private $name;
    
    function __construct($name)
    
    {
    
    $this->name = $name;
    
    }
    
    }
    
    abstract class Tree
    
    {
    
    // создает узел (если $parentNode == NULL - корень)
    
    abstract protected function createNode(Node $node,$parentNode=NULL);
    
    // удаляет узел и все дочерние узлы
    
    abstract protected function deleteNode(Node $node);
    
    // один узел делает дочерним по отношению к другому
    
    abstract protected function attachNode(Node $node,Node $parent);
    
    // получает узел по названию
    
    abstract protected function getNode($nodeName);
    
    // преобразует дерево со всеми элементами в ассоциативный массив
    
    abstract protected function export();
    
    }
    
    // Обеспечить выполнение следующего теста:
    
    // 1. создать корень country
    
    $tree->createNode(new Node('country'));
    
    // 2. создать в нем узел kiev
    
    $tree->createNode(new Node('kiev'), $tree->getNode('country'));
    
    // 3. в узле kiev создать узел kremlin
    
    $tree->createNode(new Node('kremlin'), $tree->getNode('kiev'));
    
    // 4. в узле kremlin создать узел house
    
    $tree->createNode(new Node('house'), $tree->getNode('kremlin'));
    
    // 5. в узле kremlin создать узел tower
    
    $tree->createNode(new Node('tower'), $tree->getNode('kremlin'));
    
    // 4. в корневом узле создать узел moskow
    
    $tree->createNode(new Node('moskow'), $tree->getNode('country'));
    
    // 5. сделать узел kremlin дочерним узлом у moskow
    
    $tree->attachNode($tree->getNode('kremlin'), $tree->getNode('moskow'));
    
    // 6. в узле kiev создать узел maidan
    
    $tree->createNode(new Node('maidan'), $tree->getNode('kiev'));
    
    // 7. удалить узел kiev
    
    $tree->deleteNode($tree->getNode('kiev'));
    
    // 8. получить дерево в виде массива, сделать print_r
    
    print_r($tree->export());
    
    /**
    
    результатом последнего пункта должен быть следующий вывод в STDOUT:
    
    Array
    
    (
    
    [country] => Array
    
    (
    
    [moskow] => Array
    
    (
    
    [kremlin] => Array
    
    (
    
    [house] =>
    
    [tower] =>
    
    )
    
    )
    
    )
    
    )
    
    */
    Ответ написан
    1 комментарий
  • Вывод новостей с мультикатегориями

    kraso4niy
    @kraso4niy
    fullstack
    Как вариант создать отдельную таблицу для связей категория => пост, пост has many категория условно говоря или наоборот.
    Затем спарсить в эту таблицу все посты (написать метод для этого) , разделяя explode'ом (split) поле категорий в content. В итоге получите валидную организацию в бд (посредством связей) и увеличите производительность.
    В дальнейшем категории можно спарсить в nested sets алгоритм и избежать рекурсий.
    Ответ написан