Статьи

Изучение платформы Webiny: компонент StdLib

Есть поговорка о карьере разработчика:

  1. Не использует фреймворки
  2. Обнаруживает рамки
  3. Пишет свой фреймворк
  4. Не использует фреймворки

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

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

Фреймворк называется Webiny , и, хотя он и полон изобретений колес, которые они считают необходимыми , в нем есть некоторые действительно интересные компоненты, на которые стоит взглянуть. В этом вводном посте мы не будем фокусироваться на фреймворке в целом, а на самом базовом из его компонентов — StdLib.

Webiny StdLib

Нет, не то, что «стандартный». StdLib расшифровывается как Стандартная библиотека и является ядром каждого другого подкомпонента фреймворка. Это похоже на добавление зависимости или двух в случайный проект PHP, и, прежде чем вы узнаете, что происходит, Symfony / Yaml каким-то образом уже присутствует.

Помимо прочего, StdLib, как и многие другие до этого, значительно упрощает работу со скалярами, добавляя свободный объектно-ориентированный интерфейс сверху и несколько вспомогательных методов. Например, есть легкий URLObject, который содержит некоторые вспомогательные методы для работы с перенаправлением, схемами, портами и т. Д. Помимо помощи с OO-обертками, библиотека также предлагает некоторые базовые проверки, методы, помогающие создавать другие компоненты Webiny, простой синглтон черта и многое другое.

StdLib существенно отличается тем, что он реализован в виде набора черт — крайне недоиспользуемой части современной разработки PHP. Например, вышеупомянутый URLObject создается следующим образом: $this->url('http://www.webiny.com/'); потому что признак StdObject добавляется к любому классу, который нуждается в этой функции. Большинство других компонентов платформы Webiny также реализованы в виде черт из-за их изолированной природы — команда выбрала этот подход, чтобы упростить иерархическую структуру классов, стремясь к как можно меньшему числу расширений.

StdLib может использоваться в качестве отдельного пакета и может быть клонирован или «составлен» напрямую, или его можно вставить как часть всей платформы . Давайте посмотрим, что он предлагает?

Характеристики

Внутренне StdLib состоит из двух вложенных библиотек. Одним из них является набор исключений, который должен использоваться только в том случае, если вы намереваетесь создавать дополнительные компоненты Webiny (подробнее об этом в будущих уроках). Другой — это библиотека StdObject, которая содержит функциональность, о которой мы говорили ранее.

Кроме того, библиотека содержит черты, которые используют эти саблибы.

ComponentTrait

ComponentTrait полезен, только если вы создаете дополнительные компоненты Webiny — то, с чем мы пока не будем иметь дело. Сейчас мы пропустим это.

FactoryLoaderTrait

FactoryLoaderTrait полезен для вызова экземпляров классов, которые были определены динамически. Например:

 $className = 'myNameSpace\myClass'; $argument1 = 'Hello'; $argument2 = 'World'; $mustBe = 'myNameSpace\mySubClass'; 

Чтобы создать экземпляр myClass с аргументами «Hello» и «World», убедившись, что экземпляр имеет тип mySubClass , вы можете воспользоваться следующими двумя подходами:

 // standard PHP try { $instance = new $className($argument1, $argument2); if (!($instance instanceof $mustBe)) { throw new Exception("Instances don't match!"); } } catch (Exception $e) { // Handle exception } 
 // FactoryLoaderTrait approach try { $instance = $this->factory($className, $mustBe, [$argument1, $argument2]); } catch (Exception $e) { // Handle exception } 

Как видите, второй способ немного короче. Конечно, полезность этой черты в лучшем случае сомнительна, особенно если учесть, что имена динамических классов — это не то, что нужно использовать слишком много, но если принять во внимание уровень стандартизации, такая функция может распространиться на всю вашу организацию / инфраструктуру. , преимущества становятся очевидными. Подход этой черты является чуть более чем «стандартом кодирования» в реализации динамического класса, но он может быть ценным.

SingletonTrait

SingletonTrait мгновенно превращает ваш класс в синглтон. В Интернете ведутся широкие дискуссии о «плохой» природе синглетонов — не только древние писания, подобные этим, но даже некоторые из наших старых постов обсуждают это — но есть вероятность, что вам нужен один и у вас не будет достойного DI реализация контейнера, чтобы использовать вместо этого, это здесь.

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

Если вы новичок в синглетах, этот пост может помочь .

Еще одна вещь, о которой стоит упомянуть в этой реализации, это тот факт, что эта черта реализует открытый метод init и защищенный метод _init , которые выполняются в этом порядке после создания экземпляра.

Это полезно, потому что вы можете использовать его в качестве механизма инициализации после создания для дальнейшей настройки вашего экземпляра-одиночки без необходимости полагаться на его конструктор — возможно, у вашего класса уже есть определенный конструктор, и все, что вам нужно, — это превратить его в одноэлементный. , но режим работы синглтона нуждается в дополнительной настройке? Идеально init для init .

StdLibTrait

Эта черта является комбинацией StdObjectTrait и ValidatorTrait. Сам по себе StdLibTrait содержит несколько помощников кодирования и декодирования json, которые на данный момент довольно просты, а также метод сериализации и десериализации, который выполняет практически те же функции, что и аналоги PHP. Это могло быть тем местом, где вместо этого можно использовать Serializer Symfony как проверенный в бою и мультиформатный вспомогательный компонент.

ValidatorTrait

Начиная с ValidatorTrait, это простая коллекция нативных PHP-методов для проверки типа, но переписанная так, что они являются частью класса. Я не уверен в причинах этого, так как API остается почти полностью идентичным ( self::isArray() vs is_array() ), но я предполагаю, что это как-то связано с сохранением расширяемости компонента — возможностью обновления этих нативные методы без необходимости изменения API на уровне библиотеки в дальнейшем гарантированно станут бесценным преимуществом.

В одной части валидатор использует StdObjectWrapper, который является частью суббиблиотеки StdObject — он использует обертки Webiny OO для скаляров и формат url, чтобы обеспечить свободный интерфейс для проверки этих типов.

StdObjectTrait

Это ядро ​​компонента StdLib, основная часть . Он предоставляет классу, который использует эту черту, возможность порождать экземпляры ArrayObject, UrlObject, StringObject и DateTimeObject с помощью соответствующего вспомогательного метода.

StringObject

Возможно, самый простой из всех, этот объект позволяет использовать строки в качестве объектов.

 $string = $this->str("My string"); 

Экземпляр будет изначально содержать константу кодирования (по умолчанию UTF8) и некоторые вспомогательные методы, такие как length , wordCount и subStringCount , которые все являются наглядно полезными, а также некоторые нативные функции PHP, вновь обернутые в методы класса. Через ManipulatorTrait , общий для всех объектов StdObject, StringObject также имеет доступ к методам, которые его изменяют — trim является наиболее знакомым, но также содержит методы для добавления, добавления, добавления косой черты и многого другого.

Огромным преимуществом этого подхода является не только возможность цепочки вызовов к строковому объекту, но также автозаполнение, которое такой интерфейс обеспечивает для вашей IDE:

 $string = $this->str("This is a string"); echo $string->hash()->padLeft(45, "testing"); 

В одной строке мы хешируем строку и дополняем оставшиеся слоты символов слева от нее словом «тестирование», пока не получим 45 символов. Результатом является testif72017485fbf6423499baf9b240daa14f5f095a1 . Это вряд ли становится проще, и это очень легко читается.

В качестве другого примера посмотрите этот документ из документации:

 $string = new StringObject('Some test string.'); $string->caseUpper()->trimRight('.')->replace(' test'); // SOME STRING 

Конечно, объект реализует __toString так что его можно напрямую использовать в виде строки. По совпадению, все другие объекты в StdLib также реализуют этот метод, и их можно напрямую печатать, создавая выходные данные, которые, как вы ожидаете, будут генерировать их необъектные аналоги.

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

ArrayObject

Как и StringObject, ArrayObject предлагает простой интерфейс для манипулирования массивами. Естественно, он удобен для итераций, поэтому вы можете просто проходить через него как любой массив с foreach, ведя себя почти как собственный массив.

 $array = new ArrayObject(['one', 'two', 'three']); $array->first(); // StringObject 'one' $array->append('four')->prepend('zero'); // ['zero', 'one', 'two', 'three', 'four'] 

Обратите внимание, что получение элементов из этого формата массива создает StdObjects, а не фактические скаляры. Возвращаемое значение всегда будет StdObjectAbstract тип StdObjectAbstract . Строки производят StringObject, массивы производят ArrayObject, а числа, как это ни странно и непоследовательно и последовательно, создают экземпляр StdObjectWrapper со свойством _value установленным на фактическое число. Если элемент является классом, этот класс также оборачивается оболочкой. Например:

 $array = $this->arr([1, "2", new myClass(1, 2)]); var_dump($array->last()); 

Это дает нам:

Я не уверен, что я чувствую по этому поводу. С одной стороны, это очень непротиворечиво, так как мы всегда получаем StdObjectWrapper в той или иной форме или форме, но с другой стороны, если я имею дело с массивом классов, мне наплевать на эту оболочку. Конечно, есть способ получить реальное значение из любого объекта Webiny StdLib — у каждого есть метод val который извлекает базовое значение, содержащееся в нем.

Для всех различных манипулятивных методов, к которым массивы имеют доступ с помощью этой черты, см. Манипулятор . Я нахожу синтаксис цепного уровня особенно полезным — возможность перейти в многомерный массив с помощью key1.key2.key3 в качестве индекса — весьма впечатляющая экономия времени:

 $array = [ 'k1' => 'test', 'k2' => [ 'k3' => [ 'k4' => 'deepest' ] ] ]; $a = new ArrayObject($array); $a->keyNested('k2.k3.k4', 'webiny'); $a->keyNested('k2.k3.k5', 'anotherElement'); echo $a->keyNested('k2.k3.k4'); // webiny echo $a->keyNested('k2.k3.k5'); // anotherElement 

URLObject

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

Странно то, что URLObject не расширяет StringObject. Для меня расширение имело бы смысл видеть, поскольку в данном случае они, по сути, являются строками, а первый выиграл бы от манипулятивных методов второго. Существуют также гораздо лучшие библиотеки для манипулирования URL-адресами, поэтому я не вижу преимущества использования этой библиотеки. Одним из примеров, который приходит на ум, является превосходная библиотека URL-адресов PHP League, которая делает все это и многое, многое другое, с дополнительным преимуществом полного тестирования и активной поддержки более десятка высококвалифицированных разработчиков.

DateTimeObject

Наконец, есть DateTimeObject. Благодаря вспомогательным методам, разрывающимся по швам, объект DateTime обеспечивает более плавный, естественный интерфейс к собственному классу PHP DateTime и помогает вам решать проблемы, связанные со временем:

 $dt = new DateTimeObject('3 months ago'); echo $dt; // 2013-02-12 17:00:36 $dt->add('10 days')->sub('5 hours'); // 2013-02-22 12:00:36 

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

Это не значит, что DateTimeObject не имеет своего применения — он поддерживает часовые пояса по умолчанию, простые выходные данные в формате даты различных форм и размеров, простые и легкие различия в качестве более легкой альтернативы Period, удобочитаемые выходные данные «X time ago», смещение в разные часовые пояса и многое другое.

Вывод

Делая все это, платформа Webiny гарантирует, что ни один разработчик, участвующий в проекте, не будет иметь дело с нативными типами PHP. У них у всех есть свои соответствующие обертки, и они ведут себя именно так, как хотят разработчики. Это слишком амбициозно? Может быть. Но я вижу в этом интересный подход, похожий на определение стандарта кодирования перед началом работы над проектом — проблемы, возникающие на последующих этапах разработки, будут зависеть исключительно от конкретной области, что, скорее всего, сэкономит время в долгосрочной перспективе. Единственный большой недостаток, который я вижу здесь, — это use этой черты в каждом отдельном классе, которому вы хотите предоставить поддержку StdObject.

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

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