Ответы пользователя по тегу PHP
  • Что такое CORS?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    Cross-Origin.... это значит "между хостами". То есть вы делаете запросы с "localhost:3000" на "localhost:8080" или с "example.com" на "google.com", или с "example.com" на "api.example.com".

    Resource - тобишь ресурсы. Можете почитать что это такое в контексте REST или HTTP или URI.

    Sharing - ну тут я думаю тоже должно быть понятно. "обмен". То есть это правила которые определяют "можно ли чуваку получить доступ к этому ресурсу".

    Нужна эта штука для того что бы говорить "разрешает ли сервак запросы с этого орижина на этот ресурс".
    Ответ написан
    1 комментарий
  • Как правильно вывести дату php?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    А теперь прочитайте ваш код вслух. НУ вот серьезно, он же не читабелен вообще. К примеру вот:

    $from = new \DateTime('14:30');
    $to = new \DateTIme('17:00');
    
    $now = new \DateTime();
    if ($from < $now && $now < $to) {
      // ваш код
    }


    Тут просто и понятно что откуда и куда, не нужно много думать что бы это прочитать и понять что вы хотите сделать. А в вашем варианте.... словом код ревью не пройдет.
    Ответ написан
    1 комментарий
  • Как правильно составить условие?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    'total_cost' => $row['new_cost'] ?? $row['total_cost'];
    Ответ написан
  • Как отследить нужную комбинацию в массиве?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    давайте думать. У нас есть массив с числами. У нас есть еще один массив с числами. Нам нужно проверить находится ли в первом массиве все элементы из второго. То есть что нам нужно, это сделать пересечени массивов (array_intersect) которое выделит "совпадения", убрать возможность повторений (array_unique) и посчитать количество. Если оно равно 5-ти - значит все хорошо.
    Ответ написан
    1 комментарий
  • Как по-изящнее переписать несколько php echo строк?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    printf

    printf('<a href="blog/all/%s">%s</a>', $row['OriginalAlias'], $row['Title']);
    Ответ написан
    2 комментария
  • Как правильно реализовать паттерн MVC?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    Ваша задача - не зацикливаться на аббривиатуре MVC и подумать над тем, как отделить HTTP от приложения. Для упрощения представьте что:

    - view - это HTTP запрос и ответ. Это представление данных которое требует от сервера клиент.
    - model - это ваше приложение которое ничего не знает о HTTP
    - controller - это не один класс, а возможно целая цепочка классов, чья задача - абстрагирование модели от HTTP. Можно воспринимать ее как цепочку адаптеров. Запрос приходит в один адаптер - там разруливаем маршрутизацию, нашли контроллер - передаем дальше. Со временем адаптеры могут добавляться, например для добавления CORS или аутентификации могут быть дополнительные "адаптеры" (гуглить про middelwares, PSR-7 и т.д.)

    Так же не забываем про принцип инверсии контроля (Inversion of control). Фреймворк должен вызывать ваш код а не ваш код дергать фреймворк. То есть именно контроллеры дергают модель а не наоборот. Модель ничего не должна знать ни о view ни о контроллерах.

    Удачи.

    p.s. я описал mediating controller MVC, оригинальный же паттерн MVC 79-ого года на бэкэнде не применим.

    p.p.s. Перед имплементацией MVC рекомендую познакомиться с такими инструментами как composer. И например роутер сходу не писать свой. И ради бога не используйте PHP как шаблонизатор (гуглить про то что такое XSS), возьмите twig.

    p.p.p.s https://github.com/pmjones/adr - рекомендую ознакомиться.
    Ответ написан
  • Как создать и выйти из бесконечного цикла в PHP?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    php.net/manual/ru/language.control-structures.php - читаем

    И вообще где используются бесконечные циклы?


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

    Другой пример - игры. Каждый кадр - это одна итерация бесконечного цикла. Цикл продолжается с момента запуска игры до того момента как мы выключили игру.
    Ответ написан
    Комментировать
  • Как зная год месяц день недели, определить дату?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    echo (new DateTime($year . '-' . $month))
          ->modify('first ' . $day ' . of this month') // first monday of this month
          ->format(\DateTime::ATOM);
    Ответ написан
    Комментировать
  • Можно ли задать ожидание порядка выполнения методов мока в phpunit?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    и нужно ли это делать в юнит-тестах?


    не нужно, поскольку вы таким образом жестко привязываете себя к текущей реализации. Чем меньше ваши тесты знают о тестируемом коде - тем лучше. В целом примите за правило что мокать нужно либо интерфейсы (причем ваши желательно, инверсия зависимости и все такое), либо то что общается с внешним миром. Все остальное желательно не мокать что бы не завязывать тесты на имплементацию.
    Ответ написан
    1 комментарий
  • Как использовать контроллеры и модели в фреймворках?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    модель - это очень абстрактное слово. Заглянем в словарь:

    Модель - представление предмета, системы...


    Итого - "моделью" в контексте MV* является... модель вашего приложения, то есть что собственно приложение делает. Главное не заблуждаться что это "способ доступа к данным", там по сути все что относится к обработке данных. То есть контроллеры максимум могут просить модель что-то сделать или дать представление каких-то данных, что бы контроллер сформировал из этого view (HTTP ответ в контексте PHP фреймворка).

    Есть еще такая штука - Action-Domain-Responder называется, там чуть меньше "абстрактных слов" но суть примерно та же что и у MVC.

    Но вернемся к вопросу

    Не могу до конца понять как использовать модели, где они хранятся.


    Это вам решать. Slim - это очень простой HTTP фреймворк. Его задача - дать вам контроллеры, а модель - ваша задача ее реализовать. Вы можете вооружиться контейнером зависимостей или сервис локатором даже, и дергать нужные сервисы, которые уже будут делать дела.

    Суть всего этого - абстрагировать "модель" то есть ваше приложения от HTTP. Что бы потом можно было реюзать код вашего приложения с другими интерфейсами (как правило консольными командами или очередями).

    Ссылку на "зачем нужна инъекция зависимостей" вам уже привели, я лишь добавлю более-менее полезное чтиво на тему разделения ответственноси и слоеных архитектур в slim: codereview.stackexchange.com/questions/93914/slim-...
    Ответ написан
    3 комментария
  • Как перебрать цифры с нулями впереди?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    Number('000042'); // 42

    и еще метод sort принимает пользовательскую функцию в качестве аргумента.... ну или я не правильно понял вашу задачу.

    если на оборот надо из циферок строки - гуглить "javascript pad string leading zero"
    Ответ написан
  • Как не нарушать SOLID?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    вы путаете инверсию контроля и инверсию зависимости. Давайте по порядку кратенько.

    Зачем нам нужны контроллеры или различные представления данных

    Зачем нам в принципе контроллер? Что он делает? Для упрощения не будет воспринимать контроллер как "один объект" и вместо этого представим себе его как целый слой. Так же заменим слово "модель" словом "приложение".

    Задача контроллера - принять и обработать запрос и выдать ответ. По сути в контексте WEB наш HTTP запрос и ответ это представление, которое хочет получить клиент (браузер, мобильное приложение, SPA, что угодно). HTTP - это интерфейс пользователя (UI) для нашего web-приложения.

    Например что бы независеть от реализации клиента и что бы было удобно мы передаем даты в формате iso 8601 (пример: 2016-07-14T19:40:12Z). Это удобно что бы быть независимым от реализации клиента или сервера. Но это не удобно для нашего приложения. В приложении скорее всего нам удобнее всего работать с объектом типа DateTime. То есть приложение использует абсолютно другое представление.

    Мы могли бы прямо в приложении конвертить DateTime в iso 8601 но тогда мы делаем наше приложение привязанным к одному конкретному представлению, которое хочет получить клиент. К примеру по каким-нибудь причинам известным только темным богам, вам вдруг понадобится быстро прикрутить интеграцию с другим сервисом и те же данные гонять уже в RFC2822. И стало быть уже приложению нужно париться о еще одном представлении.

    Мы могли бы сделать какие-то адаптеры у приложения, и дергать их в зависимости от потребностей, но тогда опять же наше приложение все еще знает о представлении, которое ему собственно не нужно. То есть у нас есть зависимость приложения от его UI что... похоже на "не лучшую идею". И тут на помощь приходит Inversion of Control.

    Что такое Inversion of Control

    Тут название само говорит за себя. Допустим у нас был объект A который дергал объект B, причем объект A по сути и не должен ничего знать об объекте B потому то это не его дело. Принцип инверсии контроля говорит нам о том, что в таких ситуациях именно B должно вызывать A, таким образом меняя направление потока управления. Это позволяет нам уменьшить связанность и повысить зацепление компонентов нашей системы. Так же сделав это у нас может появиться объект C который так же будет дергать объект A. Если говорить о UI - мы просто можем сделать несколько реализаций UI.

    То есть если еще упростить - фреймворк должен дергать ваш код, а не код дергать код фреймворка. Тем самым мы снижаем связанность одного от другого.

    Роутер и контроллеры как реализация UI

    Что бы отвязать приложение от логики формирования представления, вынесем это все в отдельный "слой" и назовем этот слой - контроллеры. Точнее это будет как цепочка адаптеров. Один адаптер (фронт-контроллер по сути) получает Request и делает какие-нибудь вещи с ним. Например проверяет можем ли мы вообще делать подобный запрос. Другой адаптер вызывает роутер и выясняет какой дальше адаптер вызвать. Если следующий адаптер не вызван - надо вернуть 404-ую ошибку. Если же все пошло хорошо - мы вызываем еще один адаптер, который уже будет конвертировать HTTP запрос в какое-то действие приложения (вызов метода приложения по сути).

    Так а инверсия зависимости это что?

    Инверсия зависимости - очень похожа на инверсию контроля но действует чуть по другому. Проще всего будет вглянуть на картинку:

    Dependency_inversion.png

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

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

    Нужно ли соблюдать принцип инверсии зависимости в случае контроллеров?

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

    будет ли правильным передавать зависимости в роутинге

    Это уже вопрос реализации IoC. Конкретно вы хотите получить что-то вроде Dependency Injection. Вы можете забрать зависимости из аргументов метода экшена. или аргументов конструктора контроллера.... или просто использовать контейнер зависимостей внутри контроллера.... это совершенно не важно. Контроллеры это то место где высокая связанность на компоненты фреймворка более чем допустимы.

    С другой стороны у вас теперь роутинг совмещает обязанность маршрутизации и разруливания зависимостей. Сами понимаете что это как-то нарушает прицип единой ответственности. Этим может заниматься Controller Resolver какой-нибудь.
    Ответ написан
    2 комментария
  • Оффлайн справочник по php и mysql?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    php.net/download-docs.php

    p.s. даже 3g-ка нет?
    Ответ написан
    Комментировать
  • Как наследуются функций в PHP?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    функции не наследуются.

    > Возвращает baseClass, я голову сломал.

    константа эта (__CLASS__) возвращает имя класса в котором вызываемый код вы пишите. Если вам нужен тип инстанса - используйте get_class($this). Он будет возвращать именно тип инстанса с которым вы работаете.

    p.s. завязывать код на имена типов - плохая идея.
    Ответ написан
  • Можно ли использовать firebase из PHP для замены MySQL?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    firebase из PHP для замены MySQL?


    В этом ровным счетом никакого смысла. Хотя да, можно. Но лучше вообще отказаться от PHP в этом ключе. То есть где-то 80% задач бэкэнда берет на себя firebase (CRUD операции) а вам как бэкэнд разработчику остается только самое вкусное (платежи, кастомная логика, все что не умеет firebase словом).

    На первый взгляд - бесплатная база данных, почему бы не использовать.


    Это больше чем база данных.
    Ответ написан
    4 комментария
  • Как организовать работу оповещений на сервисе?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    Думаю это не очень красиво.


    1) при изменении состояния объекта кидайте ивент об этом или явно вызывайте нотификатор
    2) нотификатор добавляет в очередь задачу (beanstalkd, rabbitmq, etc)
    3) очередь ответственна за отслеживание статуса задачи
    4) воркеры берут задачи из очереди и собственно занимаются отправкой.
    Ответ написан
  • Как лучше организовать отложенные http-запросы?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    beanstalkd

    либо я вас не понял. В этом случае лучше опишите какую задачу вы хотите решить.
    Ответ написан
    4 комментария
  • Вопрос логики: как правильно назвать метод?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    лайки штука интересная. Для начала сам по себе "лайк" это не сущность, это связь между пользователем и фотографией. Идем дальше.

    Сущность юзера должна знать о лайках? Скорее всего нет. Сущность которую лайкают должна знать о лайках? По сути тоже нет, но это удобно. Потому пусть будет так.

    Итого минимум который нам нужен для того что бы сделай лайки - это одностороння many-to-many связь. Если брать например Doctrine реализация будет примерно такой:

    class Photo {
        /**
         * @type User[]|ArrayCollection
         */
        private $likes;
    
        public function __construct(/** ... */) {
            // тут какой-то еще код
            $this->likes = new ArrayCollection();
        }
    
        // ... другая логика
    
        public function like(User $user)
        {
              $this->likes->add($user);
        }
    }


    Итого имеем интерфейс:

    $photo->like($user);

    мол мы отправляем сообщение объекту $photo что он кому-то нравится, и передаем кому. А тот уже сам внутри все разрулит.

    Поскольку вы захотели сделать Like сущностью, подозреваю что вы хотите знать еще дополнительную информацию вроде "когда кто-то что-то лайкнул" и т.д. Зачем - не мое дело. Но просто давайте чуть изменим имплементацию метода не меняя интерфейса:

    public function like(User $user) 
    {
        $this->likes->add(Like::photo($this, $user));
    }


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

    Еще такой интересный момент, что мы можем все методы вроде `isLikedBy` и т.д. вынести прямо в сущность при желании. Для этого в случае доктрины можно воспользоваться extra lazy ассоциациями и методом matching у коллекции которая вместо обхода объектов может и sql выполнить по критерии какой-то.

    Ну и что бы совсем закончить. Пока у нас корнем агрегата сущностей (состоящего из Photo и User) корнем выступает сущность Photo. Но может статься так что лайки у нас могут быть еще сложнее. Например нам надо учитывать репосты и считать количество лайков из этого расчета (как вконтактике например). Тогда с реляционной базой мы быстро начинаем проигрывать и мы можем взять Neo4J например для того что бы хранить лайки как граф. Тогда все удобно и быстро. И тогда можно вытащить логику работы с лайками наверх так что сущности сами о ней вообще ничего не будут знать.

    Но это наверное уже совсем другая история.
    Ответ написан
    4 комментария