Стандарты PSR

Оглавление (нажмите, чтобы открыть):

PSR-1. Основной стандарт написания кода

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

Ключевые слова «ДОЛЖЕН», «НЕ ДОЛЖЕН», «ТРЕБУЕТСЯ», «БУДЕТ», «НЕ БУДЕТ», «СЛЕДУЕТ», «НЕ СЛЕДУЕТ», «РЕКОМЕНДУЕТСЯ», «МОЖЕТ», и «ОПЦИОНАЛЬНО» в этом документе должны быть истолкованы как описано в RFC 2119.

1. Обзор

Файлы ДОЛЖНЫ использовать только и теги.

Файлы ДОЛЖНЫ использовать только UTF-8 без BOM для PHP кода.

Файлам СЛЕДУЕТ либо объявлять знаки (классы, функции, константы, и т.д.) либо оказывать побочный эффект (например, генерировать вывод, изменять .ini настройки, и т.д.) но НЕ СЛЕДУЕТ делать и то и другое.

Пространства имен и классы ДОЛЖНЫ следовать PSR-0.

Имена классов ДОЛЖНЫ быть объявлены используя StudlyCaps .

Константы класса ДОЛЖНЫ быть объявлены в верхнем регистре с подчеркиванием в качестве разделителей.

Имена методов ДОЛЖНЫ быть объявлены используя camelCase .

2. Файлы

2.1. PHP Теги

PHP код ДОЛЖЕН использовать длинные теги или сокращённый echo-тэг теги; другие варианты тегов НЕ ДОЛЖНЫ использоваться.

2.2. Кодировка символов

PHP код ДОЛЖЕН использовать только UTF-8 без BOM.

2.3. Побочные эффекты

Файлу СЛЕДУЕТ объявлять новые сущности (классы, функции, константы, и т.д.), и не вызывать побочные эффекты, или ему СЛЕДУЕТ выполнять логику с побочным эффектом, но НЕ СЛЕДУЕТ делать и то и другое.

Фраза «побочные эффекты» означает выполнение логики непосредственно не связанной с объявлением классов, функций, констант и так далее. То есть при подключении такого файла производятся некоторые действия, а не только обяъвление новых классов и функций.

«Побочные эффекты« включают, но не ограничиваются следующими действиями: генерация вывода, явное использование require или include , подключение к внешним сервисам, изменение настроек php.ini, генерация ошибок или исключений, изменение глобальных или статичных переменных, чтение или запись в файл, и так далее.

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

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

3. Пространства имен и имена классов

Пространства имен и классы ДОЛЖНЫ следовать PSR-0.

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

Имена классов ДОЛЖНЫ быть объявлены используя StudlyCaps .

Код написанный на PHP 5.3 и старше ДОЛЖЕН использовать пространства имен.

4. Константы, свойства и методы класса

Термин «класс» относится ко всем классам, интерфейсам и трейтам.

4.1. Константы

Константы класса ДОЛЖНЫ быть объявлены в верхнем регистре с использованием подчеркиваний в качестве разделителей. Например:

4.2. Свойства

Это руководство намеренно избегает любых рекомендаций, касающихся использования $StudlyCaps , $camelCase , или $under_score для имен свойств.

Независимо от соглашения именования его СЛЕДУЕТ применять последовательно в разумных пределах. Этот предел может быть на уровне поставщика, на уровне пакета, на уровне класса, или уровне метода.

4.3. Методы

Имена методов ДОЛЖНЫ быть объявлены используя camelCase .

Битва стандартов: PSR-0 против PSR-4

Если вы уже достаточно хорошо знаете PHP, вы наверняка слышали о стандартах PSR-0 и PSR-4, которые позволяют автоматически загружать требуемые классы в момент их вызова, без использования таких конструкций как require и include . В заметке мы сравним эти два подхода, разберемся в проблемах и приемуществах каждого и подумаем, что все-таки лучше.

PSR-0 смотрит на пространств имен класса и на его основе генерирует путь к файлу. Например, класс \Zend\Mail\Message соответствует файлу /path/to/project/lib/vendor/Zend/Mail/Message.php .

PSR-0 также поддерживает символы подчеркивания в имени класса в качестве альтернативы неймспейсам для версий PHP Zend_Mail_Message так же будет загружен из /path/to/project/lib/vendor/Zend/Mail/Message.php .

Composer

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

Это в лучшем случае бардак и избыточность. Директории src и test обязательно должны содержать директорию с именем вендора и названием пакета. По этой причине некоторые головастые PHP разработчики собрались и написали новый стандарт, который должен решить проблему.

PSR-4 разрабатывался с расчетом возможности работы вместе с PSR-0, если это необходимо, не заменяя его. Он конечно может, но не обязан. Основная цель PSR-4 это выбросить устаревшие решения, использовавшиеся до выхода PHP 5.3 и построить более простую структуру директорий пакета. С PSR-4, описанная выше структура пакета будет выглядеть так:

Выбранный подход

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

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

Кроме того, стандарт явно заявляет, что автозагрузчик PSR-4 никогда не должен выбрасывать исключения и вызывать ошибки просто потому, что в проекте может быть зарегистрировано несколько автозагрузчиков. Если не удалось загрузить класс одним загрузчиком, нужно оставить возможность сделать это другим. Остановка процесса при исключении в PSR-0 доставляло неприятности. Если же требуется сбор информации о сбое, следует использовать PSR-3 совместимый логгер или любые другие средства.

Согласно примеру, загрузка классов с помощью PSR-4 из следующей структуры:

будет выглядеть так:

При вызове new \Foo\Bar\Qux\Quux; класс будет загружен из первого зарегистрированного каталога, в то время как new Foo\Bar\Qux\QuuxTest; будет загружен из второго.

Заключение

Ни один способ не является серебряной пулей в вопросах автозагрузки. Каждый подход имеет свои плюсы и минусы. PSR-4 использует более простую структуру каталогов, но иногда не совсем очевидную, например, мы не сможем узнать точный путь к файлу, просто взглянув на имя класса. PSR-0 в свою очередь создает избыточную, но при этом очевидную структуру директорий. Он так же поддерживает старые добрые имена классов с подчеркиваниями, за что любим некоторыми разработчиками, застрявшими на старых версиях PHP.

Рекомендации к стандартам оформления кода на PHP

PSR (Proposing a Standards Recommendation) рекомендации к стандартам оформления кода на PHP, принятые группой совместимости фреймворков PHP-FIG (Framework Interoperability Group). Сводную таблицу смотрите по ссылке PHP Coding Style Notes.

На данный момент стандарт PSR состоит из четырёх разделов.

Стандарт описывает именование классов в пространствах имен (namespace) для их автозагрузки.

  • Имя класса должно содержать путь к файлу с описанием класса.

В общем виде это выглядит так:

Символ _ в имени класса конвертируется в DIRECTORY_SEPARATOR (разделитель директорий).

Стандарт описывает общие правила оформления кода.

  • Использование только тэгов и
  • Кодировка только UTF-8 без BOM для PHP кода
  • Пространства имен и классы должны соответствовать PSR-0
  • Запрещено смешивать в одном файле классов, функций, констант, настроек (ini_set) и конструкций языка (echo)
  • Классы именуются в стиле StudlyCaps
  • Константы пишутся в верхнем регистре. В качестве разделителя между слов используется знак подчеркивания
  • Методы именуются в стиле camelCase

Стандарт более подробно раскрывает оформление кода.

  • Строгое следование PSR-1
  • В качестве отступов использовать 4 пробела вместо табуляции
  • Длина строки с кодом 80-120 символов
  • Обязательным условием является наличие пустой строки после дериктив use и namespace
  • Открывающая фигурная скобка при объявлении класса или функции должня быть на новой строке, а закрывающая — на новой строке после тела класса или функции
  • Область видимости (public/protected/private) необходимо объявлять у всех свойств и методов класса; abstract и final объявлять перед областью видимости; static — после нее
  • Разделять пробелом управляющие конструкции (if/elseif/while/for/foraech/try-catch) и скобку. Пробелы между круглыми скобками и их содержимым не допустимы. Открывающая фигурная скобка должна быть в конце строки

Подробнее о PSR-4. Улучшенная автозагрузка

PSR — это рекомендации по оформлению кода на PHP. Я писал ранее вводную статью об этом. Я хочу подготовить ряд статей о каждом из принятых на данный момент стандартов и поскольку нужно будет приводить много кода, то для каждого из стандартов будет отдельная статья. Я думал всю информацию уместить в один пост с примерами, но, как следует изучив вопрос понял, что это получится громадная простыня текста, которую сложно будет воспринять. Эта статья будет посвящена стандарту PSR-4. Пока что проработано 5 стандартов:

PSR-4 – Улучшенная автозагрузка

Слова «НЕОБХОДИМО» / «ДОЛЖНО» («MUST»), «НЕДОПУСТИМО» («MUST NOT»), «ТРЕБУЕТСЯ» («REQUIRED»), «НУЖНО» («SHALL»), «НЕ ПОЗВОЛЯЕТСЯ» («SHALL NOT»), «СЛЕДУЕТ» («SHOULD»), «НЕ СЛЕДУЕТ» («SHOULD NOT»), «РЕКОМЕНДУЕТСЯ» («RECOMMENDED»), «МОЖЕТ» / «ВОЗМОЖНО» («MAY») и «НЕОБЯЗАТЕЛЬНО» («OPTIONAL») в этом документе следует понимать так, как это описано в RFC 2119 (и его переводе).

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

  • Здесь под «классом» следует понимать также интерфейсы ( interface ), примеси ( trait ) и иные подобные конструкции.
  • Полностью определённое имя класса должно иметь следующую структуру: \ (\ )*\
  • Полностью определённое имя класса ДОЛЖНО начинаться с пространства имён высшего уровня, указывающего на разработчика кода («имя производителя»).
  • Полностью определённое имя класса МОЖЕТ включать в себя одно или более подпространств имён.
  • Полностью определённое имя класса ДОЛЖНО заканчиваться именем класса.
  • Символ _ («знак подчёркивания») не обладает никаким особенным значением в полностью определённом имени класса.
  • В полностью определённом имени класса МОЖНО использовать буквенные символы в любых комбинациях нижнего и верхнего регистров.
  • Все имена классов ДОЛЖНЫ быть использованы с соблюдением регистрочувствительности.

При загрузке файла, соответствующего полностью определённому имени класса, используются следующие правила:

  • Последовательность из одного и более пространств и подпространств имён (не включая ведущий разделитель пространств имён) в полностью определённом имени класса (т.н. «префикс пространств имён») должна соответствовать хотя бы одному «базовому каталогу».
  • Последовательность подпространств имён после «префикса пространства имён» соответствует подкаталогу в «базовом каталоге», при этом разделители пространств имён \ соответствуют разделителям каталогов / . Имя подкаталога и имя подпространства имён ДОЛЖНЫ совпадать вплоть до регистра символов.
  • Имя класса, завершающее собой полностью определённое имя, соответствует имени файла с расширением .php . Имя файла и имя класса ДОЛЖНЫ совпадать вплоть до регистра символов.

В реализации автозагрузчика НЕДОПУСТИМО порождать исключения, ошибочные ситуации любого уровня и НЕ СЛЕДУЕТ возвращать какое бы то ни было значение.

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

Полностью определённое имя класса

Префикс пространства имён

Итоговый путь к файлу

\Acme\Log\Writer\File_Writer Acme\Log\Writer ./acme-log-writer/lib/ ./acme-log-writer/lib/File_Writer.php \Aura\Web\Response\Status Aura\Web /path/to/aura-web/src/ /path/to/aura-web/src/Response/Status.php \Symfony\Core\Request Symfony\Core ./vendor/Symfony/Core/ ./vendor/Symfony/Core/Request.php \Zend\Acl Zend /usr/includes/Zend/ /usr/includes/Zend/Acl.php

Примеры реализации автозагрузчиков, соответствующих данной спецификации, представлены в файле с примерами. Примеры реализации НЕДОПУСТИМО рассматривать как часть спецификации, т.к. они МОГУТ измениться в любое время.

PHP Standards Recommendations

According to the PSR Workflow Bylaw each PSR has a status as it is being worked on. Once a proposal has passed the Entrance Vote it will be listed here as “Draft”. Unless a PSR is marked as “Accepted” it is subject to change. Draft can change drastically, but Review will only have minor changes.

As also described in the PSR Workflow Bylaw. The Editor, or editors, of a proposal are the essentially the lead contributors and writers of the PSRs and they are supported by two voting members. Those voting members are the Coordinator who is responsible for managing the review stage and votes; and a second sponsor.

Что такое PSR

PHP Standards Recommendations — это набор рекомендаций для разработчиков на PHP. Отношение к PSR разное: от полного неприятия, то фанатичной преданности. Сам по себе PSR появился как копирование Java Community Process (ага, опять Java!). Основное назначение PSR в том, чтобы предоставить PHP-разработчикам некие общие концепции, которые уже были проверены и отработаны.

На сегодняшний день существует 20 рекомендаций PSR. Часть из них находится в активном статусе, другие в виде черновиков. Есть «заброшенные» и отмененные рекомендации. В общем «движуха» достаточно активная. Попробуем во всём этом разобраться.

Стандарт или рекомендация?

В названии PHP Standards Recommendations неудачная игра слов — «стандарт» и «рекомендация» (стандартные рекомендации). Под стандартом обычно понимают то, чему следует строго и обязательно следовать. Рекомендация же, наоборот, лишь предлагает, но не обязывает. По своей сути PSR однозначно рекомендация, которая не требует исполнения.

Группа PHP Framework Interop Group предлагает рекомендации в качестве помощи PHP-разработчикам. То есть смысл в том, чтобы прийти к унификации при решении некоторых задач. Здесь есть некая тонкая грань, когда PSR начинает описывать не просто абстрактную теорию как нужно делать, а предлагает уже конкретный php-код, что во многих случаях может вызывать непонимание или даже неприятие. Но в любом случае PSR однозначно не отвечает за архитектуру приложения, а значит следовать рекомендациям или нет полностью ложится на решение разработчика.

Фундаментальные рекомендации, по сути стандарты

Самое важное, чего добилась группа PHP-FIG — это всё-таки заставила php-программистов следовать единому стилю написание кода. За это отвечают два стандарта:

  • PSR-1: Basic Coding Standard
  • PSR-12: Extended Coding Style

На самом деле это лишь второстепенный фактор: качество кода никак не связано с его форматированием. Но, когда код предполагается для обозрения, то общепринятый формат упрощает его чтение. По факту же эти рекомендации больше всего востребованы в программах редакторах. Например я привык к стилю форматирования CodeIgniter. Но мне не сложно нажать автоформат в Visual Studio Code и получить полное соответствие PSR-1/12. Более того, если я встречаю чужую библиотеку, которая неряшливо оформлена, то опять же привести код в понятный — это один клик мышью.

Другим фундаментальным стандартном стал PSR-4: Autoloader (старый и отмененный PSR-0). В нём описан алгоритм подключения файлов классов для spl_autoload_register() . Это очень важная рекомендация, которая не только упростила подход к именованию файлов, но и решила вопрос со структурой каталогов. В конечном итоге это даже сыграло положительную роль и с разделением пространства имён (namespace).

ООП интерфейсы

Остальные рекомендации представляют собой обычные интерфейсы для создания своих классов. Читать такие PSR лучше с конца — исходного кода. Тогда будет понятно реальное назначение. По какой-то причине описание PSR начинается с многословного бла-бла-бла и многие разработчики воспринимают именно эту часть текста как безусловный «стандарт». Происходит подмена понятий, дескать, если не следовать этой рекомендации, то код становится устаревшим и плохим.

Мастер Йода рекомендует:  Настройка поисковых сниппетов – FAQ от Google

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

PSR-3: Logger Interface

Назначение — ведение журнала протоколирования. То есть не просто лог в файл или на экран, а некая система, которая работает не только с текстом сообщения, но и его кодом важности. Этот код описан в документе RFC 5424:

  • Emergency: system is unusable
  • Alert: action must be taken immediately
  • Critical: critical conditions
  • Error: error conditions
  • Warning: warning conditions
  • Notice: normal but significant condition
  • Informational: informational messages
  • Debug: debug-level messages

То есть когда отправляется какое-то сообщение, то присваивается его код важности (это в самом простом понимании). Что предлагает PSR-3? Элементарную вещь — готовый интерфейс Psr\Log\LoggerInterface с методами:

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

Дальше. Если предположить, что несколько разработчиков логов сделают разные реализации, то они могу быть совместимы между собой, поскольку все реализуют интерфейс Psr\Log\LoggerInterface . Получается вроде как унификация.

И здесь важный момент. Если в приложении нужен лог (а это очень частая задача), то не значит, что нужно обязательно делать его со всеми методами PSR-3. То есть всегда следует идти от реальной задачи и не создавать лишние связи/классы/файлы там, где этого не требуется.

PSR-6: Caching Interface
PSR-16: Common Interface for Caching Libraries

Интерфейс, который призван привести работу с разными видами кэширование к единым методам. То есть не важно как именно будет реализовано кэширование проекта, например через Memcached или обычные файлы, на «публику» следует отдать единые методы. PSR-6 предлагает их с избытком, видимо рассчитывая на особенности кэширующих библиотек.

PSR-7: HTTP message interfaces

Назначение этого стандарта уже вызывает массу вопросов. Цель, вроде как понятна — обеспечить работу с http-протоколом. Ради этого был придуман интерфейс с множеством методов. При этом реализуется еще RequestInterface и ResponseInterface . Мне кажется здесь прослеживается очередное желание подражать Java, поскольку PSR-7 предполагает использовать ООП для работы с http. Всё это хорошо, только в PHP с испокон веков принято работать с помощью $_POST, $_GET, $_SERVER и т.п. Это не просто глобальные переменные, а суперглобальные: имеющие не только особую важность, но и значительно упрощающие работу с http (или даже так). PSR-7 предлагает вместо простых строчек кода использовать сложное нагромождение классов.

PSR-11: Container interface

Описывает два метода для контейнера зависимостей. Это ООП-паттерн «Dependency injection» (я его ещё не публиковал). В DI предполагается, что есть некий контейнер, который хранит все зависимости. Скажем есть несколько классов, которые вначале добавляются/регистрируются в этом контейнере, а уже после «вытягиваются» из него по мере необходимости. PSR-11 предлагает, что получение это метод get() и has() для проверки существования зависимости.

PSR-11 направлен на разработчиков «модульных» фреймворков, где есть необходимость подключения сторонних (или своих) модулей/библиотек. Вместо обычного инстанцирования класса через new используется метод контейнера, например add() , а получение с помощью get() . Вот пример одной из библиотек.

Тут всё сильно завязано на внутреннюю архитектуру используемого фреймворка — если он сложный, то скорее всего использует свою реализацию, которой следует придерживаться. Для простых же вещей обычного ООП-подхода более чем достаточно.

PSR-13: Link definition interfaces

Смысл этой рекомендации в том, чтобы унифицировать методы работы с ссылками. Предлагается сразу несколько интерфейсов, методы которых должны возвращать разные атрибуты. Я не знаю где это вообще нужно, поскольку небольшой обёртки над стандартной parse_url() обычно хватает более чем.

PSR-14: Event Dispatcher

По сути это попытка создать ООП-паттерн Observer (Наблюдатель). Я его уже как-то описывал для Java. (Нужно будет, конечно, довыкладывать все остальные php-паттерны. ) Назначение PSR-14 в реализации событийной модели в приложении. Я никогда не сталкивался с подобной схемой, возможно это также завязка на какой-то фреймворк, но нюанс в том, что в PHP уже есть стандартные (без кавычек) интерфейсы для реализации полноценного паттерна Observer (SplSubject, SplObjectStorage и SplObserver).

PSR-15: HTTP Server Request Handlers
PSR-17: HTTP Factories
PSR-18: HTTP Client

Эти рекомендации развивают PSR-7. То есть опять же, если приложению как-то активно и своеобразно использует http-методы, то наверное есть смысл воспользоваться этими PSR.

Итоги

Нужны ли рекомендации PSR? На мой взгляд да, нужны. Самые главные стандарты — это стиль кодирования и автозагрузка — это то, что реально востребовано. Остальные рекомендации рассчитаны на специфичные задачи. Наверное правильней и честней было бы прямо указать, дескать это реализовано в таком-то фреймворке, давайте использовать аналогично. Поскольку этого нет, то и нет понимания того, где именно нужно использовать рекомендацию вне конкретного фреймворка.

Тут ещё следует отметить, что PHP-FIG формируют люди, которые имеют свои проекты. В каждом из них свои «велосипеды» и большинство несовместимы между собой. Каждый разработчик считает что его подход лучший, но это не значит, что все должны ему следовать. PHP очень гибкий язык, поэтому может быть множество реализаций одной задачи. Рекомендации PSR это взгляд с какой-то одной стороны и не всегда лучший. Скажем Symfony покинула группу PHP-FIG, а влияние Symfony очень велико: выкиньте из Laravel все Symfony-зависимости и что там останется? А если и все остальные сторонние модули. Так что в PHP-FIG всё не так гладко.

Хотя, возможно, настанет момент, когда крупные разработчики смогут предложить свою альтернативу, более конкретную и понятную, чем текущие рекомендации PSR. Ну а пока следовать им или нет, каждый решает сам. 🙂

Стандарты PSR

Частная коллекция качественных материалов для тех, кто делает сайты

  • Фотошоп-мастер2000+ уроков по фотошопу
  • Фото-монстр300+ уроков для фотографов
  • Видео-смайл200+ уроков по видеообработке
  • Жизнь в стиле «Кайдзен» Техники и приемы для гармоничной и сбалансированной жизни

В этом разделе помещены уроки по PHP скриптам, которые Вы сможете использовать на своих ресурсах.

Фильтрация данных с помощью zend-filter

Когда речь идёт о безопасности веб-сайта, то фраза «фильтруйте всё, экранируйте всё» всегда будет актуальна. Сегодня поговорим о фильтрации данных.

Контекстное экранирование с помощью zend-escaper

Обеспечение безопасности веб-сайта — это не только защита от SQL инъекций, но и протекция от межсайтового скриптинга (XSS), межсайтовой подделки запросов (CSRF) и от других видов атак. В частности, вам нужно очень осторожно подходить к формированию HTML, CSS и JavaScript кода.

Подключение Zend модулей к Expressive

Expressive 2 поддерживает возможность подключения других ZF компонент по специальной схеме. Не всем нравится данное решение. В этой статье мы расскажем как улучшили процесс подключение нескольких модулей.

Совет: отправка информации в Google Analytics через API

Предположим, что вам необходимо отправить какую-то информацию в Google Analytics из серверного скрипта. Как это сделать. Ответ в этой заметке.

Подборка PHP песочниц

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

Совет: активация отображения всех ошибок в PHP

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

Агент

PHP парсер юзер агента с поддержкой Laravel, работающий на базе библиотеки Mobile Detect.

PSR-0 или PSR-4, и как правильно построить структуру проекта?

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

Первый вопрос который меня интересует это PSR-0 или PSR-4. На сколько я понял по состоянию на 21 октября 2014 года PSR-0 был помечен как устаревший. В настоящее время рекомендуется использовать PSR-4 в качестве замены, но PSR-1 и PSR-2 ссылаются на PSR-0, а про PSR-3 я вообще как-то не нашел русскоязычной информации, словно такого стандарта нет.

Второй вопрос связан с иерархией по стандарту PSR-0 или PSR-4.

В примерах приводят следующее:

насколько я понимаю
/path/to/project/ это путь к проекту и данный путь нигде не фигурирует, это та директория из которой запускается основной index.php
./lib/ это папка в которой я должен хранить свои библиотеки
./vendor/ это папка назначение которой я не понимаю, так как поставщик насколько я понимаю идет дальше
в итоге насколько я понял путь строится так

это соответствует пространству имен

но в других примерах я встречал следующее:
вместо «lib» используют «src» а каталога vendor попросту нет.
или подобного рода структуру

в итоге честно говоря я запутался в том как правильно надо строить свои каталоги, какие папки обязательные какие нет, когда использовать src, когда lib, когда tests, почему в некоторых структурах приходится дважды указывать имя поставщика и имя пкета и т.д.

Скорее всего тут все очень просто, но у меня почему-то вызывает диссонанс в примерах с разных источников.

На всякий случай приведу пример иерархии своей CMS системы которую я разрабатываю:

  • Вопрос задан более трёх лет назад
  • 8188 просмотров

Первый вопрос который меня интересует это PSR-0 или PSR-4. На сколько я понял по состоянию на 21 октября 2014 года PSR-0 был помечен как устаревший.

про PSR-3 я вообще как-то не нашел русскоязычной информации, словно такого стандарта нет

/path/to/project/ это путь к проекту и данный путь нигде не фигурирует, это та директория из которой запускается основной index.php

Да, это пусть к PHP файлам проекта. Но index.php обычно выносят в отдельный каталог (например, /public), а все классы проекта хранятся, например, в /src (или /lib или ещё как угодно). В конфигурации веб-сервера запрещают отправлять запросы к любым файлам, не лежащим в /public, благодаря этому /public/index.php является единственной точкой входа для внешних запросов.

./vendor это папка назначение которой я не понимаю

Это папка для сторонних библиотек, используемых в вашем проекте. Используется composer’ом. Внутрь лезть особо причин нет, composer сам решит как ему там всё разложить. Свои классы вы туда тоже не должны писать.

в итоге честно говоря я запутался в том как правильно надо строить свои каталоги, какие папки обязательные какие нет, когда использовать src, когда lib, когда tests, почему в некоторых структурах приходится дважды указывать имя поставщика и имя пкета и т.д.

src и lib — скажем так, синонимы. Кому как больше нравится. Главное, что внутри лежат сами PHP файлы проекта, следующие стандарту PSR-4. Лежат там только файлы, написанные авторами проекта. Поэтому нет смысла класть vendor внутрь src (или lib).
test — каталог для тестов проекта.
В папке vendor имя поставщика и имя проекта могут совпадать, вот они и дублируются.

Так как вы изобретаете свой велосипед, то и структуру каталогов делайте свою, или посмотрите на популярные CMS/фреймворки, но везде будет по-разному. Joomla, WordPress, Yii, Zend Framework, Symfony.

Я придерживаюсь такой структуры:

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

Это папка для сторонних библиотек, используемых в вашем проекте. Используется composer’ом. Внутрь лезть особо причин нет, composer сам решит как ему там всё разложить. Свои классы вы туда тоже не должны писать.

а что если мы не используем в проекте composer. Я работал с подобными вещами при разработке на Java но с PHP сталкиваться не приходилось. Насколько я понял это своего рода надстройки над ide или отдельной программы которая внедряется в проект и контролирует включение тех или иных файлов в проект согласно зависимостям которые где-то прописаны. Зависимости эти скачиваются из стороннего хранилища и помещаются в указанную папку с библиотеками. Верно ил мое предположение что данная утилита хороша при разработки множества разных проектов и бессмысленна если речь идет о разработке одного проекта (CMS) который в свою логику включает систему зависимостей компонент от библиотек с возможностью получить их с нашего сервера. Грубо говоря если оператор подключает компоненту к сайту а она требует библиотеку которой у него сейчас нет, то она автоматически скачается ему с нашего сервера (напоминаю что речь идет щас о нашей разработке написанной на hp а не о composer).

я просмотрел вашу структуру и обратил внимание на то, что в папке public у вас лежит сразу и основной исполняемый файл и шаблон, причем насколько я понял шаблон у вас один для всех страниц, в своем же проекте я использую механизм при котором разрешается использовать для разных страниц разные шаблоны, как вам удается реализовать подобное, поделитесь опытом. Кроме этого как я понимаю так как мы закрываем доступ для всех папок кроме public это значит, что все js, php файлы используемые в ajax, css и файлы шаблонов должна располагаться также в папке public

src и lib — скажем так, синонимы. Кому как больше нравится. Главное, что внутри лежат сами PHP файлы проекта, следующие стандарту PSR-4. Лежат там только файлы, написанные авторами проекта. Поэтому нет смысла класть vendor внутрь src (или lib).
test — каталог для тестов проекта.
В папке vendor имя поставщика и имя проекта могут совпадать, вот они и дублируются.

насколько я вас понял

должно соответствовать пространству имен

Четыре столпа PSR

Мастер-класс по Symfony завершили, теперь пополним теперь рубрику ответов на вопросы.

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

Здравствуйте. Хотелось бы узнать ваше мнение о размышлении над PHP-FIG. Прошу прощения за сумбурность – трудно сформулировать мысль.

По сути FIG (Framework Interoperability Group) – группа взаимодействия framework’ов. Стандарты же называются PSR (PHP Standard Recommendations) – стандартные рекомендации PHP.

Но пол интернета кипит тем, что это именно стандарты и нужно следовать только им. Не следуешь – не нормальный программист.

То есть группа взаимодействия framework’ов пишет стандарты по работе с языком, что странно.

И меня беспокоит беспрекословное следование этим стандартам.

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

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

Не понятна суть этого стандарта.

По сути – нам доступно два метода: has и get. Но прокидывать куда-то контейнер – плохая идея. Если его прокинуть, то он превращается в сервис-локатор, что само по себе имеет минусы.

Правильнее – настроить контейнер и получать из него определенный класс, в который в глубину будут автоматически инжектиться остальные зависимости. При этом применение даже в framework’ах всего этого вызывает сомнение – при замене контейнера все-равно придется переписывать все те места, в которых происходит заполнение контейнера.

В том-же symfony – это происходит внутри бандлов, в laravel в провайдерах. Что делает невозможным легкую замену контейнеру. Можно было бы написать interface для контейнера, но тут уже получится большой костыль – все контейнеры биндят зависимости по разному и имеют разный функционал. Разве нет?

PSR-15: HTTP Server Request Handlers

Тут мы имеем RequestHandlerInterface и MiddlewareInterface.

В каждом по одному методу:

– handle(ServerRequestInterface $request): ResponseInterface; – process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface;

Также – не ясно зачем это нужно?

RequestHandlerInterface – не вижу ни одной причины менять его. Если нужно будет менять его – придется менять весь framework, т.к по сути – это его каркас.

MiddlewareInterface – в стандарте даже не имеет связи с RequestHandlerInterface. И в чем сложность – написать свой middleware внутри которого вызывать метод какого-либо подключенной зависимости?

Мастер Йода рекомендует:  Способы повышения производительности и безопасности сайта

Также – не ясна причина, из-за которой будет необходимо поменять request|response. Прокидывать внутрь проекта request|respone – плохо. Разве нет? И даже если нужно будет поменять их – при правильной логике придется поправить только в middleware и в контроллерах. Тот-же symfony до сих пор использует свой http foundation.

Для каких-то вещей, вроде, роутера (у вас есть в уроках) – можно прокинуть интерфейс и написать adapter, необходимость замены в будущем остальных вещей – вызывает сомнение, но и это при отделении логики можно будет легко произвести. Есть паттерны, разделение проекта на части. Что еще нужно?

Если я захочу поменять кэш, например – напишу адаптер для интерфейса нужной мне библиотеки.

Для тех же, кто в ответ на «У всех свои проблемы» отвечает «У большинства проблемы одинаковые» – будет полностью писать на определенном framework’е – laravel, symfony, yii и.т.д., их библиотеки и будет завязан на те-же бандлы, контейнеры, конфиги, доктрину и т.д., и не будет заморачиваться работой в стиле: «сегодня заменю библиотеку для config, через месяц заменю http, еще через месяц роутер» и т.д.

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

Хотел бы услышать ваше мнение на это рассуждение.

Здравствуйте! Да, я часто говорю и пишу про PSR-ы. Раз непонятных моментов и претензий к ним возникает много, то стоит разделить рекомендации на смысловые группы с сайта PHP-FIG, но в более удобном порядке:

  • PSR-1: Basic Coding Standard
  • PSR-12: Extended Coding Style Guide
  • PSR-4: Improved Autoloading
  • PSR-3: Logger Interface
  • PSR-6: Caching Interface
  • PSR-11: Container Interface
  • PSR-13: Hypermedia Links
  • PSR-14: Event Dispatcher
  • PSR-16: Simple Cache
  • PSR-7: HTTP Message Interfaces
  • PSR-15: HTTP Handlers
  • PSR-17: HTTP Factories
  • PSR-18: HTTP Client

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

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

Так что первая группа – это.

Всеобщий Code Style

Пока в других языках не утихают споры про «табы vs пробелы», пока каждая компания выпускает свои гайды:

и пока там до сих пор рушатся чьи-то судьбы

знайте, что в PHP с форматированием кода нам повезло.

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

Для борьбы с бесполезным разнообразием стилей теперь для PHP есть конкретно описанные рекомендации PSR-1, PSR-2 и PSR-12.

Пусть рождённые до принятия этих рекомендаций WordPress и Yii1 любят или не любят ставить или не ставить пробелы до/после скобок и называть поля в snake_case/camelCase, но сейчас с новыми фреймворками нам проще. Это даёт хорошие бонусы:

  • Никому не нужно изобретать свои стили, как все это делают для Java. Можно всё делать по единым для всего мира PSR.
  • Умные IDE содержат автоформатирование, настроенное по PSR. Стоит нажать Reformat Code в PhpStorm и код автоматически выровнится.
  • Есть PHP CodeSniffer, который может в консоли проверить и автоматически исправить код по тем же PSR.

В итоге если все программисты привыкнут оформлять код одинаково по PSR, то будет проще всем.

А в языке Go с этим всё ещё строже, так как при неверном форматировании вылетит ошибка компиляции.

Так что PSR для Code Style – это как правила хорошего тона. Можете не придерживаться, но тогда постоянно вам будут об этом напоминать.

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

Идея PSR-4 проста: путь в namespace и имя класса совпадают с именами папок и файла.

Стоит где-то в одном месте указать автозагрузчику, что базовый неймспейс App соответствует папке src , так сразу класс App\Blog\Entity\Post спокойно можно будет найти в файле src/Blog/Entity/Post.php любому PSR-4-совместимому загрузчику.

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

Делая свой мини-фреймворк или мини-CMS вам может быть лень подключать Composer. И может показаться, что проще сложить классы по-особому и сочинить свой загрузчик с spl_autoload_register для импорта ваших классов из файлов. Если показалось, но вы решили выложить этот код на GitHub, то ущипните себя за что-нибудь.

Почему? Потому что как только я возьму вашу CMS и начну на ней что-то делать, то её кода мне скорее всего не хватит. Помимо него я захочу подключить готовый Markdown-парсер и почтовик вроде SwiftMailer. Или даже без них захочу подключить PHPUnit или Codeception для тестов. И для этого мне. всё равно придётся подключать Composer. И после этого ещё и скрещивать ваш автозагрузчик с имеющимся в Composer, чтобы они теперь не мешали друг-другу.

Так что в любой ситуации удобнее будет придерживаться именования файлов по PSR-4 и подключить Composer. Другим PSR-ам следуйте по вкусу, а автозагрузку не ломайте.

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

Обобщённые интерфейсы

Для каких-то вещей, вроде, роутера (у вас есть в уроках) – можно прокинуть интерфейс и написать adapter, необходимость замены в будущем остальных вещей – вызывает сомнение, но и это при отделении логики можно будет легко произвести. Есть паттерны, разделение проекта на части. Что еще нужно?

Если я захочу поменять кэш, например – напишу адаптер для интерфейса нужной мне библиотеки.

Это вопрос к списку:

  • PSR-3: Logger Interface
  • PSR-6: Caching Interface
  • PSR-16: Simple Cache
  • PSR-14: Event Dispatcher
  • PSR-18: HTTP Client

Адаптеры для своего кода – это понятно. Но что насчёт не своего?

Вася пишет библиотеку для определения города по IP-адресу. Сочинил класс Locator :

Теперь подумал, что неплохо бы вынести HTTP-клиент. Написал свой:

Ну и лучше интерфейс для клиента предусмотреть:

И неплохо бы добавить логер. Написал свой логер:

Потом решил, что было бы неплохо не ограничиваться файловыми логами, а объявить интерфейс:

чтобы другие программисты могли вместо файлового свои логеры через адаптеры подсовывать.

Ну и чтобы слишком часто сторонний сервис локации не дёргать, решил добавить кэш:

Всё, библиотека готова. Можно выкладывать на GitHub.

Теперь чтобы подключить эту библиотеку к своему проекту я просто делаю:

composer require vasya/ip-locator

и пишу свои адаптеры для него

Но проекты обычно большие. И так через Composer я установил себе восемь чужих библиотек. И вижу, что к каждой библиотеке её автор написал свои собственные Logger и Cache.

Итого я имею восемь библиотек со своими логерами и кэшами и мне для них нужно сочинить шестнадцать адаптеров. Грустно.

Но что за глобальная несправедливость такая? Почему тысячи программистов для своих тысяч библиотек тысячи раз пишут логеры и кэшеры? Вот бы было классно, если бы все программисты договорились и сделали один общий LoggerInterface и CacheInterface.

Вот они и договорились в PHP-FIG и сделали всё общее.

Если теперь Васе нужно в своём компоненте сделать логирование, то вместо своего самописа он спокойно принимает Psr\Log :

Теперь я могу передать ему любой PSR-совместимый клиент и PSR-логер фреймворка напрямую без адаптеров:

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

Если теперь я задумал через Composer установить себе восемь чужих библиотек, то если все они принимают PSR-овские логер и кэш, то я спокойно закину в них свои monolog/monolog и zendframework/zend-cache без всяких адаптеров.

В итоге имеем общепринятые интерфейсы LoggerInterface , CacheInterface , EventDispatcherInterface и рассматриваемый нами далее HttpClientInterface . Быстро и удобно.

Теперь Вася вместо кучи кода:

может сочинить всего один файл:

и в нём завязаться на общепринятые интерфейсы.

Теперь клиент, логер и кэш к нему можно подключить любые готовые на усмотрение другого программиста.

Framework Interoperability сэкономил время на написание кода автору и на написание адаптеров пользователю библиотеки.

Не понятна суть этого стандарта.

По сути – нам доступно два метода: has и get. Но прокидывать куда-то контейнер – плохая идея. Если его прокинуть, то он превращается в сервис-локатор, что само по себе имеет минусы.

Правильнее – настроить контейнер и получать из него определенный класс, в который в глубину будут автоматически инжектиться остальные зависимости. При этом применение даже в framework’ах всего этого вызывает сомнение – при замене контейнера все-равно придется переписывать все те места, в которых происходит заполнение контейнера.

В том-же symfony – это происходит внутри бандлов, в laravel в провайдерах. Что делает невозможным легкую замену контейнеру. Можно было бы написать interface для контейнера, но тут уже получится большой костыль – все контейнеры биндят зависимости по разному и имеют разный функционал. Разве нет?

Да, прокидывать куда-то контейнер – плохая идея. И если его прокинуть, то он превращается в сервис-локатор, что само по себе имеет минусы.

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

Например, классу Slim\App или ControllerResolver любого фреймворка или микрофреймворка он нужен, чтобы доставать оттуда контроллер через $container->get($controllerName) .

Также к шине команд league/tactician прилагается готовый резолвер ContainerLocator, который достаёт обработчик команды из PSR-контейнера как из локатора через $container->get($handlerName) .

При замене контейнера все-равно придется переписывать все те места, в которых происходит заполнение контейнера.

Код Application , ControllerResolver и HandlerLocator всех библиотек и микрофреймворков использует контейнер только на чтение методами has и get . Им не интересно, чем и как мы переданный контейнер заполняем.

И если мне при разработке проекта на микрофреймворке Slim 3 с удобным роутером не нравился его примитивный контейнер Slim\Container без автовайринга, ленивой загрузки и фабрик, то я его могу заменить на zend/service-manager и передать в new Slim\App($container) уже его.

И установив Tactician я могу ему спокойно передать любой контейнер из моего Yii, Symfony, Laravel, Slim или Zend, так как все они реализуют общий ContainerInterface .

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

Обобщение работы с HTTP

С общими интерфейсами компонентов разобрались. Они описывают простые конкретные библиотеки.

Из этой группы к ним можно отнести PSR-18 для описания компонента HTTP Client. А PSR-15 уже является обобщением для построения целых фреймворков.

Вся группа работает поверх PSR-7. С него и начнём.

Откуда всё это пошло и зачем понадобилось?

С данными запроса в PHP ввиду его процедурного прошлого мы можем работать напрямую через набор разрозненных глобальных массивов $_SERVER , $_GET , $_POST , $_FILES , $_COOKIES . У $_SESSION особый случай, так как сессии работают через файлы и Cookies.

Но передавать такую большую пачку было бы дико:

В синхронных PHP-приложениях можно и не передавать, а дёргать напрямую из этих массивов. Но в асинхронном режиме это не сработает.

Для удобства можно их совместить в массив:

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

Но вместо процедурной работы с переменными:

удобнее работать с объектом $request :

Для этого в PHP тоже можно написать свой класс:

И всё бы работало в реале и легко эмулировалось в тестах.

В экосистеме NodeJS в наборе http.* есть устоявшиеся классы ClientRequest IncomingMessage и ServerResponse и многие фреймворки пишут на них.

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

PSR-7 как раз и решил ввести общие RequestInterface , ServerRequestInterface и ResponseInterface , заточенные на работу без оглядки на суперглобальные массивы. И сделал их иммутабельными для безопасной работы в асинхронных EventLoop-ах.

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

Можно придти к мысли, что сделав обобщённые Request и Response можно будет не делать общие утилиты и контроллеры.

Каждый фреймворк это делал по-разному. Но после прихода PSR-7 на данный момент имеем:

  • популярный набор symfony/http-foundation, на котором работают Symfony и Laravel;
  • универсальный psr/http-message для написания фреймворконезависимого кода;
  • свои классы Request и Response других фреймворков вроде Yii;

В Symfony используются свои классы, но имеется мост symfony/psr-http-message-bridge для конвертации Symfony\HttpFoundation в Psr\Message и обратно. В итоге в Symfony и Laravel в контроллер можно принимать хоть HttpFoundation\Request , хоть универсальный Psr\Message\Request .

На сайте жены по бисероплетению я сделал виджет вывода фотографий из Instagram через Instagram PHP Scrapper, подключающийся через mashape/unirest-php.

Другие библиотеки для доступа к чужим API разных SMS-провайдеров, рассылок и других сервисов работают то напрямую через CURL, то через file_get_contents , то через Guzzle.

В итоге наставив кучу библиотек тоже получаем такой же зоопарк способов подключения. И чтобы банально указать им всем один прокси-сервер или добавить кэш приходится ковыряться в настройках каждого клиента и переопределять методы, где жёстко вписан curl.

Раз мы определились с общим Request, то в идеале для той же унификации сейчас появился повод перевести все библиотеки на использование PSR-18, чтобы им всем можно было передать один и тот же Psr\HttpClient , чтобы я мог подсунуть им логирующий, проксирующий или кеширующий декоратор для HttpClientInterface .

PSR-15: HTTP Server Request Handlers

Также не ясно зачем это нужно?

RequestHandlerInterface – не вижу ни одной причины менять его. Если нужно будет менять его – придется менять весь framework, т.к по сути – это его каркас.

MiddlewareInterface – в стандарте даже не имеет связи с RequestHandlerInterface. И в чем сложность – написать свой middleware внутри которого вызывать метод какого-либо подключенной зависимости?

PSR-17: HTTP Factories

Также – не ясна причина, из-за которой будет необходимо поменять request|response. Прокидывать внутрь проекта request|respone – плохо. Разве нет? И даже если нужно будет поменять их – при правильной логике придется поправить только в middleware и в контроллерах. Тот-же symfony до сих пор использует свой http foundation.

Вот мы и дошли до контроллеров и посредников.

Имея общие Request и Response помимо обобщённой работы в синхронных или асинхронных фреймворках мы можем обобщить и сами контроллеры с посредниками.

API своего проекта я сделал на микрофреймворке Zend Expressive. И мне понадобилось определять IP-адрес комментатора. Что мне делать? Можно сочинить самому цикл по обходу заголовков. Но вместо этого я подключил готовый IpAddress Middleware.

С появлением PSR-15 теперь можно безболезненно делиться наборами middleware единого формата. Например, я могу сочинить и из проекта в проект копировать свой TrailingSlashMiddleware для автообрезки слеша в конце адреса страницы:

Или выложу на GitHub. Но пока есть проблема. В PSR есть только интерфейс ResponseInterface , но нет самого класса Response . Я использую Zend\Diactoros\Response из пакета zend-diactoros:

Но в другом проекте у меня вместо него Slim\Http\Response из пакета slim/http и пришлось бы переписать:

И чтобы внутри универсальных Middleware не вписывать жёстко new Response там вместо этого можем использовать фабрику:

Здесь мы создаём Response через метод createResponse фабрики:

Теперь никакие классы Zend и Slim мы здесь не используем, поэтому TrailingSlashMiddleware можно выложить на GitHub и подключать к любому PSR-15-совместимому фреймворку. Достаточно только подсунуть ему фабрику из zend-diactoros или slim/http.

Также не ясна причина, из-за которой будет необходимо поменять request и response.

Из вышеизложенного можем сделать вывод, что внутри своего проекта Request и Response мы менять не собираемся. Они меняются лишь когда мы наш TrailingSlashMiddleware переносим из фреймворка во фреймворк или подключаем к нескольким проектам на разных фреймворках.

Мастер Йода рекомендует:  Создание Minecraft на Unity3D. Часть вторая. Генерация мира

MiddlewareInterface позволяют делать универсальные переносимые middleware, которые можно выкладывать на GitHub и использовать в проектах на разных синхронных или асинхронных фреймворках.

RequestHandlerInterface аналогично бонусом позволяет делать фреймворконезависимые контроллеры. Но не для выкладывания, а для своего проекта. Получаем бонус в том, что можно начать проект на Zend Expressive, а потом перейти на Slim3 или Laravel практически не переписывая контроллеры и посредники.

Следовать или нет

Главный вопрос. Нужно ли всё это?

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

Выгоды от PSR-ов не видны в своём проекте со своими компонентами, так как свой код мы можем сочинять как хотим. Когда каждый программист велосипедит свой Logger и Cache проблем не возникает.

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

Здесь-то и становится видна польза универсальности и стандартизации для общемировой совместимости компонентов и фреймворков друг с другом.

Да, разные фреймворки следуют им в разной степени. Кто-то модифицирует свой код. Кто то прикладывает адаптеры, как Symfony выложила psr-bridge и убрав PSR-16 из компонета symfony/cache добавила к нему переходник Psr16Cache.

И меня беспокоит беспрекословное следование этим стандартам.

Если теперь при выборе очередной библиотеки с Packagist я увижу, что там лежит свой Logger, Container, Event Dispatcher или Cache, то мне станет грустно и я напишу issue с просьбой заменить их на PSR-овские, чтобы я и тысячи программистов с написанием адаптеров не мучались. Это разумно.

Не уверен. Обычно, адаптеры не содержат никакой логики, а являются просто мостом. Время затраченное на написание issue может легко сравниться со временем написания адаптера. Для корректной же смены данных частей, в.т.ч и фреймворка можно просто разделять код на слои. Не использовать Request\Response, передавать данные через DTO,

Так Framework Interoperability как раз и нужен для упрощения interoperability. Чтобы код был совместим из коробки без десятков адаптеров и DTO.

Но пол интернета кипит тем, что это именно стандарты и нужно следовать только им. Не следуешь – не нормальный программист.

  • Если пишешь только для себя, то пишешь как хочешь. Даже хоть без Composer.
  • Если пишешь что-то для публики и уместно следуешь общепринятому, то тебя хвалят.
  • Если пишешь публично, но ничему не следуешь, то тебя ругают.

Сегодня принято одно, завтра другое. Тот-же Symfony – вышел из FIG. А сколько недовольства было по PSR Event Dispatcher.

То, что уже принято уже кардинально не изменится. А Symfony настолько крут, что может себе позволить выйти из FIG и сделать свой набор Contracts. При этом он не следует многим PSR нативно, но тут же сам предоставляет к ним адаптеры. Недовольство — недовольством, но теперь его Cache и Event Dispatcher начнут чаще использовать не для Symfony-проектов.

Существует множество библиотек и компонентов, которые не используют PSR, но при этом достаточно известнее PHP-FIG.

Да, есть монополисты, которые ещё держатся. Но если посмотреть на некоторых, то:

  • Логер Monolog сразу внедрил PSR-3 и теперь де-факто все подключают его.
  • Guzzle впрыгнула в тренд и внедрила PSR-7. PSR-18 в пути, но давно есть готовый адаптер.

Легаси-проекты могут также приложить к себе готовый опциональный адаптер.

Интервьюировался недавно, в несколько крупных компаний недавно, и от PSR там было только – стандарты оформления кода, да composer (не PSR). Никаких Http, Middleware, Container и.т.д. PSR интерфейсов.

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

Крупные Bitrix-оиды не пользуются нэймспейсами и Composer. Крупные WordPress-ники не пользуются Git и ООП. Каждый пользуется только тем, что ему нужно и не пользуется тем, что ему неинтересно.

Framework Interoperability предоставляет обобщения для облегчения переносимости кода и компонентов между фреймворками.

Поэтому если работаете с несколькими фреймворками, пилите микросервисы на микрофреймворках, публикуете компоненты и не хотите завязываться на вендоров, то вам это нужно. Если же у вас только один проект на одном стеке на всю жизнь, то и думать ни о чём не нужно.

Сейчас стало популярно делать легковесные API для JS-фронтенда. И там вместо полноценных фреймворков проще собрать всё на микрофреймворке из компонентов. Так там PSR-ы очень кстати.

Напоследок: больше всего беспокоит то, что PHP-FIG продвигает стандарты, а не полное общество. Если бы данные моменты обсуждались на php.net гораздо большим сообществом, и реализовывались в виде SPL, то я имел бы другое мнение.

В данном же я вижу лишь продвижение интересов определенной группы людей.

В PHP уже лежат заброшенные HTTP Interface с 2014-го и Request and Response с 2020-го. Обсуждайте на здоровье всем сообществом 🙂

А в PHP-FIG участвуют именно авторы фреймворков и библиотек, знающие это изнутри.

Так что PSR-ы – вещь опциональная, но иногда полезная.

Не пропускайте новые статьи, бонусы и мастер-классы:

PSR-2. Руководство по оформлению кода

Это руководство продолжает и расширяет PSR-1, основной стандарт написания кода.

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

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

Ключевые слова «ДОЛЖЕН», «НЕ ДОЛЖЕН», «ТРЕБУЕТСЯ», «БУДЕТ», «НЕ БУДЕТ», «СЛЕДУЕТ», «НЕ СЛЕДУЕТ», «РЕКОМЕНДУЕТСЯ», «МОЖЕТ», и «ДОПОЛНИТЕЛЬНО» в этом документе должны быть истолкованы как описано в RFC 2119.

1. Обзор

Код ДОЛЖЕН следовать PSR-1.

Код ДОЛЖЕН использовать 4 пробела для отступов, не табуляцию.

НЕ ДОЛЖНО быть жесткого ограничения на длину строки; мягкое ограничение ДОЛЖНО быть 120 знаков; строкам СЛЕДУЕТ быть 80 символов или менее.

ДОЛЖНА быть одна пустая строка после объявления namespace , и ДОЛЖНА быть одна пустая строка после блока с объявлениями use .

Открывающие фигурные скобки для классов ДОЛЖНЫ быть на новой строке, и закрывающие фигурные скобки ДОЛЖНЫ быть на новой строке после тела класса.

Открывающие фигурные скобки для методов ДОЛЖНЫ быть на новой строке, и закрывающие фигурные скобки ДОЛЖНЫ быть на новой строке после тела метода.

Область видимости ДОЛЖНА быть описана у всех свойств и методов; abstract и final ДОЛЖНЫ быть описаны перед областью видимости; static ДОЛЖНО быть описано после области видимости.

Ключевые слова управляющих конструкций ДОЛЖНЫ иметь один пробел после себя; вызовы методов и функции НЕ ДОЛЖНЫ.

Открывающие фигурные скобки для управляющих конструкций ДОЛЖНЫ быть на той же строке, а закрывающие фигурные скобки ДОЛЖНЫ быть на новой строке после тела конструкции.

Открывающие круглые скобки для управляющих конструкций НЕ ДОЛЖНЫ иметь пробел после себя, а закрывающие круглые скобки для управляющих конструкций НЕ ДОЛЖНЫ иметь пробел перед собой.

1.1. Пример

Этот пример как краткий обзор включает в себя некоторые из ниже указанных правил:

2. Общее

2.1 Основной стандарт написания кода

Код ДОЛЖЕН следовать всем правилам изложенным в PSR-1.

2.2 Файлы

Все PHP файлы ДОЛЖНЫ использовать переводы строк Unix LF (linefeed).

Все PHP файлы ДОЛЖНЫ оканчиваться одной пустой строкой.

Закрывающий ?> тег ДОЛЖЕН быть исключен из файлов содержащих только PHP.

2.3. Строки

НЕ ДОЛЖНО быть жесткого ограничения на длину строки.

Мягкое ограничение на длину строки ДОЛЖНО быть 120 знаков; автоматические проверки стиля ДОЛЖНЫ предупредить но НЕ ДОЛЖНЫ выдавать ошибку на мягкие ограничения.

Строкам НЕ СЛЕДУЕТ быть длиннее 80 знаков; более длинные строки СЛЕДУЕТ разбивать на несколько последующих строк не более чем 80 знаков в каждой.

НЕ ДОЛЖНО быть замыкающий пробелов в конце строки на не пустых строках.

Пустые строки МОГУТ быть добавлены для улучшения читабельности и указания связанных блоков кода.

НЕ ДОЛЖНО быть более одного оператора в строке.

2.4. Отступы

Код ДОЛЖЕН использовать отступ в 4 пробела, и НЕ ДОЛЖЕН использовать табуляцию для отступов.

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

2.5. Ключевые слова и True/False/Null

PHP Ключевые слова ДОЛЖНЫ быть в нижнем регистре.

PHP константы true , false , и null ДОЛЖНЫ быть в нижнем регистре.

3. Объявление Пространства имен и Use

Если они присутствуют, то ДОЛЖНА быть одна пустая строка после объявления namespace .

Если они присутствуют, все объявления use ДОЛЖНЫ идти после объявления namespace .

ДОЛЖНО быть ключевое слово use на каждое объявление.

ДОЛЖНА быть одна пустая строка после блока use .

4. Классы, Свойства, и Методы

Термин «класс» относится ко всем классам, интерфейсам и трейтам.

4.1. Extends и Implements

Ключевые слова extends и implements ДОЛЖНЫ быть объявлены на той же строке, что и имя класса.

Открывающая фигурная скобка для класса ДОЛЖНА идти на своей собственной строке; закрывающая фигурная скобка для класса ДОЛЖНА идти на следующей строке после тела класса.

Список implements МОЖЕТ быть разделен на несколько строк, где каждая последующая строка с одним отступом. При этом первый элемент в списке ДОЛЖЕН быть на следующей строке, и ДОЛЖЕН быть только один интерфейс на строку.

4.2. Свойства

Область видимости ДОЛЖНА быть объявлена на все свойства.

Ключевое слово var НЕ ДОЛЖНО быть использовано для объявления свойства.

НЕ ДОЛЖНО быть более одного свойства объявленного на оператор.

Имена свойств НЕ СЛЕДУЕТ делать с подчеркиванием в качестве приставки для обозначения области видимости protected или private.

Объявление свойства выглядит следующим образом.

4.3. Методы

Область видимости ДОЛЖНА быть объявлена на все методы.

Имена методов НЕ СЛЕДУЕТ делать с подчеркиванием в качестве приставки для обозначения области видимости protected или private.

Имена методов НЕ ДОЛЖНЫ быть объявлены с пробелом после имени метода. Открывающая фигурная скобка ДОЛЖНА идти на своей собственной строке, а закрывающая фигурная скобка ДОЛЖНА быть на следующей строке после тела метода. НЕ ДОЛЖНО быть пробела после открытия круглой скобки, и НЕ ДОЛЖНО быть пробела перед закрывающей круглой скобкой.

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

4.4. Аргументы Метода

В списке аргументов, НЕ ДОЛЖНО быть пробела перед каждой запятой, и ДОЛЖЕН быть один пробел после каждой запятой.

Аргументы Метода со значениями по умолчанию должны идти в конце списка аргументов.

Список аргументов МОЖЕТ быть разделен на несколько строк, где каждая последующая строка с одним отступом. При этом первый элемент в списке ДОЛЖЕН быть на следующей строке, и ДОЛЖЕН быть только один аргумент на строку.

Когда список аргументов разделен на несколько строк, закрывающая круглая скобка и открывающая фигурная скобка ДОЛЖНЫ быть установлены вместе на их собственную строку с одним пробелом между ними.

4.5. abstract , final , и static

Если они присутствуют, то abstract и final ДОЛЖНЫ предшествовать перед объявлением области видимости.

Если присутствует объявление static , то оно ДОЛЖНО идти после объявления области видимости.

4.6. Вызовы Метода и Функции

При выполнении вызова метода или функции, НЕ ДОЛЖНО быть пробела между именем метода или функции и открывающей круглой скобкой, НЕ ДОЛЖНО быть пробела после открытия круглой скобки, а также НЕ ДОЛЖНО быть пробела перед закрывающей круглой скобкой. В списке аргументов, НЕ ДОЛЖНО быть пробела перед каждой запятой, и ДОЛЖЕН быть один пробел после каждой запятой.

Списки аргументов МОГУТ быть разделены на несколько строк, где каждая последующая строка с одним отступом. При этом первый элемент в списке ДОЛЖЕН быть на следующей строке, и ДОЛЖЕН быть только один аргумент на строку.

5. Управляющие конструкции

Общие правила стиля для управляющих конструкций следующие:

  • ДОЛЖЕН быть один пробел после ключевого слова управляющей конструкции
  • НЕ ДОЛЖНО быть пробела после открывающих круглых скобок
  • НЕ ДОЛЖНО быть пробела перед закрывающими круглыми скобками
  • ДОЛЖЕН быть один пробел между закрывающей круглой скобкой и открывающей фигурной скобкой
  • Тело конструкции должно быть с одним отступом
  • Закрывающая фигурная скобка ДОЛЖНА быть на следующей строке после тела управляющей конструкции

Тело каждой конструкции ДОЛЖНО быть заключено в фигурные скобки. Это стандартизирует вид конструкций, и уменьшает вероятность внесения ошибок при добавлении новых строк к телу управляющей конструкции.

5.1. if , elseif , else

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

Ключевое слово elseif СЛЕДУЕТ использовать вместо else if так что все управляющие ключевые слова выглядят как единые слова.

5.2. switch , case

Конструкция switch выглядит следующим образом. Обратите внимание на размещение круглых скобок, пробелов и фигурных скобок. Оператор case ДОЛЖЕН быть с одним отступом от switch , а ключевое слово break (или другое завершающее ключевое слово) ДОЛЖНО быть с таким же отступом как тело оператора case . ДОЛЖЕН быть комментарий, такой как // no break когда есть преднамеренное падение в не-пустое тело оператора case .

5.3. while , do while

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

Кроме того, оператор do while выглядит следующим образом. Обратите внимание на размещение круглых скобок, пробелов и фигурных скобок.

5.4. for

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

5.5. foreach

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

5.6. try , catch

Блок try catch выглядит следующим образом. Обратите внимание на размещение круглых скобок, пробелов и фигурных скобок.

6. Замыкания

Замыкания ДОЛЖНЫ быть объявлены с пробелом после ключевого слова function , и пробелом перед и после ключевого слова use .

Открывающая фигурная скобка ДОЛЖНА идти на той же строке, а закрывающая фигурная скобка ДОЛЖНА идти на следующей строке после тела функции.

НЕ ДОЛЖНО быть пробела после открывающей круглой скобки списка аргументов или списка переменных, и НЕ ДОЛЖНО быть пробела перед закрывающей круглой скобкой списка аргументов или списка переменных.

В списке аргументов и списке переменных НЕ ДОЛЖНО быть пробела перед каждой запятой, и ДОЛЖЕН быть один пробел после каждой запятой.

Аргументы замыкания со значениями по умолчанию должны идти в конце списка аргументов.

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

Список аргументов и список переменных МОЖЕТ быть разделен на несколько строк, где каждая последующая строка с одним отступом. При этом первый элемент в списке ДОЛЖЕН быть на следующей строке, и ДОЛЖЕН быть только один аргумент или переменная на строку.

Когда конечный список (или аргументов или переменных) разделен на несколько строк, закрывающая круглая скобка и открывающая фигурная скобка ДОЛЖНЫ быть установлены вместе на их собственную строку с одним пробелом между ними.

Ниже приведены примеры замыканий с и без списка аргументов и списка переменных разбитого на несколько строк.

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

7. Заключение

Есть много элементов оформления и практик умышленно опущенных в этом руководстве. Они включают, но не ограничиваются:

Объявление глобальных переменных и глобальных констант

Операторы и присваивания

Комментарии и блоки документации

Приставки и окончания имен классов

Будущее рекомендации МОГУТ пересмотреть и расширить это руководство для решения тех или иных элементов оформления и практик.

Добавить комментарий