📜 ⬆️ ⬇️

Web Application Theory: 2 Old Notes

Here are two of my old notes on the theory of Web applications, their structure and interaction issues. PHP examples.


Note 1. Intro, as it is trite


In this post : the general principle of dividing an application into its components, the need for a “core”, communication between parts of a web application.

Immediately to the point


In my opinion, in order to objectively look at the Web application, it is necessary, for a start, to abandon the use of the terms “MVC”, “pattern”, “OOP” and the like. It is also worth a close eye on the fundamental differences between languages, one of which is planned to develop a Web application. And then the general theoretical model of the application will consist of the following "layers":

As a layer, I call a set of classes that perform various tasks, but not beyond the scope of the activity of the current layer.
For example : if the News_Publisher class selects news from the database, the Template_Engine class processes templates, and the Smarty_Handler class, first, unifies data from the Smarty template engine's News_Publisher module, and processes the template, and secondly, is actually an implementation of the Template_Engine class method. The above can be described with the following code:
 <?php class Smarty_Handler { function view(string $tplfile, $data = null) { $smarty = new Smarty ; $smarty->assign('news', $data) ; $smarty->display($data) ; } } class Template_Engine { private static $handlerName = "" ; function setHandler(string $classname) { self :: $handlerName = $classname ; } //    Abstract Factory,      function view($tplfile, $data) { call_user_func(array(self :: $handlerName, "view"), $data) ; } } class News_Publisher { function getNews() { //            $news = array(array('title' => 'This', 'content' => 'looks like abstract factory, isnt it? :-)')) ; return $news ; } } Template_Engine :: setHandler('Smarty_Handler') ; Template_Engine :: view('myfile', News_Publisher :: getNews()) ; ?> 
<?php class Smarty_Handler { function view(string $tplfile, $data = null) { $smarty = new Smarty ; $smarty->assign('news', $data) ; $smarty->display($data) ; } } class Template_Engine { private static $handlerName = "" ; function setHandler(string $classname) { self :: $handlerName = $classname ; } // Abstract Factory, function view($tplfile, $data) { call_user_func(array(self :: $handlerName, "view"), $data) ; } } class News_Publisher { function getNews() { // $news = array(array('title' => 'This', 'content' => 'looks like abstract factory, isnt it? :-)')) ; return $news ; } } Template_Engine :: setHandler('Smarty_Handler') ; Template_Engine :: view('myfile', News_Publisher :: getNews()) ; ?>

Naturally, the Factory pattern is immediately visible here, but I promised not to pay attention to them, this was only necessary for an example.
Handler classes, by definition, should not generate any Data, other than temporary data, necessary to perform the task of linking components.
Surely you noticed that the application is missing the Kernel, at first glance the very first and indispensable component of any Web application. I admit, when the first version of this article was written, the kernel was the first layer of the application. But then I deleted it, and now I will explain why. The fact is that, as in any scientific theory, I consider “compromises” unacceptable. The scientific theory, claiming the title of the Great and Comprehensive, must necessarily have the property of applicability in all conditions and scales. Therefore, no approximations have the right to exist, since in this case, the theory is incomplete. So it is here.

If you think the kernel, in the standard sense, is a mixture of the handler and the component. Those. this is not an additional subclass, but simply a symbiosis of two existing ones, which, of course, if desired, can be easily divided into a handler and a component.
Therefore, it is proposed to get rid of the concept of "core" as such. You may argue that in this case, some set of functions that are required for any kernel (for example, the function of loading libraries, establishing a connection with a data server, etc.) will be suspended. Not at all - they fit perfectly into our structure, they are handlers of the lowest level. And given the complex structure of modern Web applications, such functions have long been combined into classes, and therefore are no different from standard handlers.
')
Thus, the Kernel is a Component that works with a fairly specific type of data - HTTP requests. But even here the core activity area is very limited - it is only necessary to accept requests and transfer them to other components for processing. It is better to work with URLs to the URLRouter component, and with the request data, to the RequestPeer component, for example.
Of course, from the programmer's side it may seem that it is very inconvenient to use the link Component - Handler - Component , and this is not the case when you need to be baptized. This is really inconvenient, and therefore it will be necessary to admit such a hateful, but so desired assumption - to let the components know about each other, i.e. allow them to transfer data in a convenient way. By the method of static calls, or, if the structure presented in the code below is used, through a link to the unifying object. Those. Do not force classes to search for each other using global variables, a list of classes and other impartial means. Still, I oppose the widespread use of this method because of laziness (and this is a very serious factor for the developer), and I will try in the next article to try to explain my point of view.
similar behavior of objects in relation to their parents can be observed in JavaScript
 <?php class Main { } class Counter { var $main ; function __construct(Main $obj) { // PHP6     $this->main = & $obj ; } function getRange() { return range(5, 20) ; } } class Joiner { var $main ; function __construct(Main $obj) { $this->main = & $obj ; } function showLine() { $range = $this->main->counter->getRange() ; echo join(", ", $range) ; } } $main = new Main ; $main->counter = new Counter($main) ; $main->joiner = new Joiner($main) ; $main->joiner->showLine() ; ?> 

Note 2. Handlers and data unification


In this post : the need for the same type of data, the connection between the components, the essence of the handlers.
In the last note, I promised that I would justify my negative attitude to the type of connection Component - Component . All the salt in the so-called "data unification". We meet with it every day - natural languages ​​are essentially a method of unifying data across the same nation / native speakers. Many such examples can be cited, and protocols and XML from the computer field.

The need for data unification is caused, for example, by establishing equality among applications or components that work with a single data source. If the developer has written an application and a component that exchange data by using a symmetrically encrypted protocol with the key sewn into their source code, the implementation of a third-party component will become a problem because there will be a need to manually decrypt data from the application. The situation is similar in Web applications.
The presence of a huge number of different implementations to solve one problem (the same template engines and CRUD libraries) imposes conditions on the structure of the application. You can’t force the CMS owner to use HTML_Flexy and not the familiar Smarty only because the engine transmits data to the template solely as a link to the object, and it’s natural for the developer to change anything in the engine or it’s not possible.
And here I consider it appropriate to use handlers. As an example:
 <?php class Fruit { var $state ; var $name ; function __construct($name, $state) { $this->name = $name ; $this->state = $state ; } } class Bucket { var $accept = "objects" ; function flush($fruits) { foreach ($fruits as $item) { echo $item->name . " is " . $item->state . "<br>" ; } } } class Fruits_Objects_Handler { function prepare($fruits) { $prepared_fruits = array() ; foreach ($fruits as $k => $v) $prepared_fruits[] = new Fruit($k, $v) ; return $prepared_fruits ; } } //         (   ,   ) $fruits = array('apple' => 'fresh', 'banana' => 'rotten', 'pear' => 'fresh', 'orange' => 'rotten') ; $bucket = new Bucket ; //   ,       if ($bucket->accept == "objects") $fruits = call_user_func(array("Fruits_Objects_Handler", "prepare"), $fruits) ; //    //            $bucket->flush($fruits) ; ?> 


Naturally, the method of selecting a handler can be one of the hundreds of the most varied, depending on the specific situation.

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


All Articles