📜 ⬆️ ⬇️

Ancestor override (dirty hack)

UPD: It’s better to avoid this of course. All this is scary, terrible, and it stinks. But it stinks a little less than VQMOD, and if you already have to patch “live” and updated, but terrible legacy, then this approach has the right to exist. But NEVER do so in projects that you are just starting or can change the architecture to a more extensible. I leave the article as it is. "In memory".




Sometimes you really want to override the behavior of the parent class, without changing its code.
For example, change the storage location of templates from files in the database ... or add caching.
or replace in ORM deletion of records by marking them as deleted.
You never know, we may wish to change.
If every programmer will go into the core of the framework or just into someone else's code, it will be porridge.
This task has many solutions. I want to offer the one I like the most.
The solution is based on __autoload () or rather on spl_autoload_register.

Most implementations of this task imply a significant amount of special code that is present in our classes “just in case” (as is done, for example, in an extension using a hook. It often happens that the developer has provided redefinition options wherever possible ... except for that place which we need.
Other solutions require substantial processing of the logic of the system, which often makes it difficult to understand and raises the threshold of entry. (for example, different variations on the event model).
')
I want everything to be simple, and at the same time as flexible as possible.
And such a solution was found:

In general, the idea is simple as sneakers:


If we cannot redefine the behavior of already declared classes, then we can control the process of declaring these classes themselves. For class loading, we are responsible for the __autoload () function.
Thus, if the class whose behavior we want to change is called via __autoload () , then by changing the behavior of __autoload () we can load the desired class from another file.
Actually, in one project, I implemented a mechanism for redefining the __autoload () behavior on the hook principle:
An application module could declare its function to load classes and register it in a certain way for execution both BEFORE the main function and after.
But we will not dwell on this implementation, because.

This is all in the past!


Finally, the time came when php 5.3 became available on most hosting sites, and there was no need to ensure compatibility with older branches.
But in 5.3, the SPL module is part of the kernel, and is available by default.
It turns out that the developers have already implemented this idea as a function spl_autoload_register.
The spl_autoload_register function simply registers our autoload function onto a stack of similar functions.
So if we write a function that loads the modified class BEFORE loading the main function, then our code will be loaded and not the standard one. On the other hand, if we want to add some variants of code autogeneration, then we can add them AFTER the main code.

Enough theory


Obviously, all redefined classes should be loaded via autoload and not directly.

Since this is a rather dirty method, and such a solution can greatly complicate code reading and debugging, it is absolutely not recommended to place such calls in the application code. All such hooks should be in the same place , in plain sight. If you are a system architect, then you should ensure that all programmers know where to add such functions and where to look for them. And also that they were at least aware that the system provides such an opportunity.

When designing it is useful to think about which of our classes can be redefined.
Sometimes this thought can push us to transfer some methods or properties to another class.
Personally, I create two classes for frequently replaced classes - a class with an implementation, and a dummy class that only inherits from a class with an implementation. The application uses a dummy. You can easily override the dummy, and calmly inherit the standard functionality where we do not change anything.

Example


common.php file containing all common code:
function start_module() { //      ....   common.php    index.php } function mainAutoload($class) { //    $filename = './class/'.$class.'.php'; if(file_exists()) require_once($filename); } 

By default, the index.php file contains:
 require_once 'common.php'; // //     spl_autoload_register('mainAutoload'); // //      start_module(); 


Suppose we decided that in our project there will be many who want to override the class soul
Then we create a class soul.php:

 class soul extends soul_basic { //   . } 


And accordingly soul_basic.php

 class soul_basic { public function good() { //       } public function evil() { //    } public function saintliness() { //    } public function business() { //    } } 


Well, already specific objects that will need a “soul” can implement or inherit from the soul not from the soul_basic , and have the functionality implemented in the soul_basic.

Now imagine that we want to change the behavior of all "souls".
Obviously, redefining the properties of the "soul" of a programmer or director or any other class that inherits from soul will not help us in this. Therefore, we create our own soul class. To do this, we modify the index.php file, for example:

 require_once 'common.php'; // //    . function century21Autoload($class) { if($class = 'soul') require_once('soul21.php'); } // //    spl_autoload_register('century21Autoload'); //     spl_autoload_register('mainAutoload'); // //      start_module(); 


Well, respectively, soul21.php:

 class soul extends soul_basic { public function good() { if(rand(0,100)>=80) parent::good(); else parent::evil(); } public function saintliness() { if($this->unit_name == 'Gundyaev') parent::bussiness(); else parent::saintliness(); } } 


PS: I am a believer and do not laugh at the church. I just separate the church as faith and the church as a business. And I don’t consider laughing from a business a sin. Although my friends and fellow priests from different denominations disagree with me ...

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


All Articles