📜 ⬆️ ⬇️

Webiny Framework. First look

There is a joke about a typical developer career:

  1. Does not use frameworks
  2. Detects frameworks
  3. Writes its frameworks
  4. Does not use frameworks

Point 4, of course, refers to the newly acquired ability to use Composer to build your own frameworks , creating them from various third-party components.

We all know that the PHP ecosystem does not suffer from the lack of various frameworks, and therefore I was a little surprised when I saw another one created relatively recently.
')
Webiny

It is called Webiny , and, being packed to the brim with the enhancements and changes they consider necessary, the framework has some really interesting components that are worth a look. In this introductory article we will not pay attention to the structure as a whole, but we will highlight its most basic components - StdLib .

Webiny StdLib


No, not that "std". StdLib underlies all other sub-components of the framework. The library serves as an auxiliary link, the same as dependency injection or symfony / Yaml in any other PHP project.

Among other things, StdLib, like many others before it, makes working with scalars much easier by adding a free object-oriented interface and some helper methods. For example, there is a lightweight URLObject that contains several methods for working with redirects, schemes, ports, etc. In addition to helping with OO wrappers, the library also offers basic validation, methods that help in assembling other Webiny components, a simple trait for implementing Singleton, and much more.

The main difference of StdLib is that it is implemented as a set of traits - a very much undervalued part of modern PHP development. For example, the above URLObject is created like this: $this->url('http://www.webiny.com/'); , because the StdObject StdObject can be added to any class that needs this functionality. Most of the other components of Webiny are also implemented on traits. Due to the isolated nature of the framework, the team chose this approach to simplify the hierarchy of classes and some expansion of capabilities.

StdLib can be used autonomously , directly from Composer, or it can be pulled out along dependencies as part of the entire framework . Let's see, what does she offer us?

Special features


Inside StdLib consists of two sub-libraries. One of them is Exception , it is used only if you intend to create additional Webiny components. The other is StdObject , which contains the functionality we talked about.

In addition, the library contains traits that are used in these sub-libraries.

ComponentTrait

ComponentTrait is only useful if you create additional Webiny components, which we will not do for now. Skip

FactoryLoaderTrait

FactoryLoaderTrait is useful in invoking class instances that have been dynamically defined. For example:

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

To instantiate the class myClass with “Hello” and “World” arguments, making sure that it is an instance of mySubClass you can use the following approaches:

 // 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 } 

As you can see, the second method is a bit shorter. I agree that the usefulness of this trait does not inspire confidence, especially since the dynamic class names are not such a thing that everyone uses, but if you take into account the scale of the entire organization / framework, the advantages of such standardization become obvious. The approach using this trait is simply a "coding standard" for the process of creating instances of dynamic classes, in some situations this can be useful.

Singletontrait

SingletonTrait instantly turns your class into Singleton. There are many extensive discussions on the Internet about the “bad nature of Singleton” - not just ancient topics , but also some of our old discussions about it. Just in case, if suddenly there is no opportunity to implement a normal DI-container, then this treit is useful to us.

Keep in mind one thing - __construct conflicts. The trait does not implement its implementation of the __construct method; it can be used both in classes that have their own implementation of the method, and in those used by other Singleton implementations . But do not forget, if you decide to use this treyt, you must adapt your class constructor according to the pattern.

If you are new to working with singletons, this post may help .

It is also necessary to note the fact that in this implementation public init and protected _init methods are implemented, and they are executed in this order after the instance is created.

This is useful because you can use it as a post-initialization mechanism for later use as a Singeton object without having to rely on your constructor. Perhaps your class still has its own constructor, and all you need is to turn it into a Singleton, but such magic needs some more fine tuning. Just for such cases this trey is perfect.

StdLibTrait

Trait is a combination of StdObjectTrait and ValidatorTrait . StdLibTrait itself contains some JSON encoding / decoding help functions, but they are rather scarce at the moment, and other PHP analogs know how to serialize into JSON. Perhaps in this place it is better to use Serializer from Symfony, a component that has been well tested by the community and has multiformat support.

Validatortrait

To begin with, ValidatorTrait is a simple collection of native PHP type checking methods wrapped in a treyt. I am not sure about its usefulness or the reasons that guided the authors, since The API remains almost identical ( self::isArray() vs is_array() ), but suppose that this is somehow related to the ability to extend the component, overload methods, implementing its own functionality.

At one point, the validator uses StdObjectWrapper to provide a smooth interface for checking these types, which in turn is part of the StdObject StdObject used in Webiny as an object-oriented wrapper for scalars and URL formatting.

StdObjectTrait

This is the core of the StdLib component, its main part . This trait provides the basic features of the standard class such classes as ArrayObject , UrlObject , StringObject and DateTimeObject .

StringObject

Perhaps the easiest of the bunch. This object allows strings to be used as objects.

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

The instance provides the ability to conveniently change the encoding (by default in the UFT8 encoding) and some auxiliary methods, such as length , wordCount and subStringCount , as well as wrappers for some of the built-in PHP functions. All this is quite useful to have on hand, right inside the class. Through ManipulatorTrait , common to all StdObjects , StringObject also has access to methods that modify it: for example, trim is the most frequently used and useful feature when working with strings.

Again, the tremendous advantage of working with traits is not only the ability to have a chain of calls over a string object, but also an automatic substitution in the IDE:


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

So, in one line we took a hash and added testing to the left to a set of 45 characters. And here is the result - testif72017485fbf6423499baf9b240daa14f5f095a1 . Hardly you can make it even easier and clearer than in the example above.

As another example, look at this code:

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

Of course, the object implements the __toString method to directly prepare it for use as a string. All other StdLib objects also have the implementation of this method for direct printing. At the exit, you can always get a primitive for further work.

These methods are too numerous to list; For more information, just see for yourself in the source .

ArrayObject

Similar to StringObject , ArrayObject offers a convenient interface for working with an array. Naturally, it is suitable for iterations through the foreach and, in general, behaves almost like a native array.

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

Note that when retrieving items from this array, instances of StdObject , not actual scalars. The return value will always be of type StdObjectAbstract . Strings produce StringObject , arrays produce ArrayObject . Numbers, which may be somewhat inconsistent, produce StdObjectWrapper instances with the _value property, in which our number is given. If the element is a class, then this class will also be wrapped. For example:

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

Here is what we get:

image

I am not sure about my feelings about this. On the one hand, this is superconsistent, we always get StdObjectWrapper in one form or another. But on the other hand, if I deal with an array of classes, I can not just forget about the wrapper and work as before: each time you need to pay some attention to this aspect. Of course, there is a way to get real values ​​from any StdLib object by calling the val method, which pulls out the base value contained inside.

For a variety of manipulative techniques with arrays based on ArrayObject , look at the corresponding trait . I find the chaining syntax especially useful, because you can go down to a multidimensional array by specifying key1.key2.key3 as an index, which, in turn, is a rather impressive time saving:

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

URLObject

This object helps to make the syntax of your URL code cleaner. It supports some common response codes, methods for signing requests, working with ports and other variables, and can also be easily manipulated — switching circuits, hosts, domains, etc. with one line of reliable code.

Strange that URLObject not inherited from StringObject . For me, the presence of inheritance would make sense, in fact, they both would benefit from each other's manipulative techniques.

There are better libraries for working with URLs, so I don’t see any particular advantages with this one. The first example that comes to mind is the great PHP League URL library , which does all this and more, has excellent code quality that has been fully tested and actively supported by more than a dozen highly qualified developers.

DatetimeObject

Finally, there is a DateTimeObject . This is a wrapper over a datetime object that provides a freer and more natural work interface, as well as helping to solve most of the problems encountered when working with time:

 $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 

Of course, DateTimeObject will be very convenient if you don’t use any library to work with time yet, but for more complex manipulations with datetime I would recommend Carbon , a little seasoned with the Period library.

It’s not to say that DateTimeObject completely useless - by default it supports work with time zones, it has a convenient date format, simple and easy diffs as an alternate Period , readable “x time ago”, time zone dependent and much more.

Conclusion


Having all this, Webiny-framework allows developers to enter the project with their native PHP code. All wrappers behave exactly as the developer expects. Too ambitious? Maybe. But I see this as an interesting approach that defines coding standards before starting work on a project - it allows you to do without problems arising in the course of further design, saving time in the long term. The only drawback I see is the need to use use in every single class in which you want StdObject support.

Project Webiny large-scale and interesting. The framework is impressive, its components cover vast areas. The question of whether this is really necessary, I leave to you. If you're wondering why I pay so much attention to him, and why this whole post, then the answer will be simple - I like to play with new things; I'm a little curious how they work from the inside.

In subsequent posts, we will look at other Webiny components and even give an example of an event-oriented application using the framework, as well as evaluate its effectiveness and flexibility. In the meantime, try it yourself and tell us about your experience.

Source: https://habr.com/ru/post/256309/


All Articles