Overriding ancestor (dirty hack)

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




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

    Most implementations of this task involve a significant amount of special code, which is present in our classes “just in case” (as is done, for example, in the extension using hook. It often happens that the developer has provided redefinition options wherever possible ... except for that place that we need.
    Other solutions require significant processing of the logic of the system, it is often difficult to understand, and increases the barrier to entry. (eg variations in the event model).

    I would like to everything was simple, and at the same time as flexible as possible,
    and such a solution was found:

    In general, the idea is simple as slippers:


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

    This is all in the past!


    Finally, there came a time when php 5.3 became available on most hosting sites, and there was no need to provide 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 in the form of the spl_autoload_register function.
    The spl_autoload_register function simply logs our autoload function onto a stack of similar functions.
    T.O. if we write a function that loads the changed 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 options for code auto-generation, then we can add them AFTER the main code.

    Enough theory


    Obviously, all redefinable classes should be loaded through autoload and not directly.

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

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

    Example


    common.php file containing all the common code:
    function start_module() {
    // здесь идет код вызова наших модулей.... расположен в common.php чтобы не захламлять index.php
    }
    function mainAutoload($class) {
        // основной код автозагрузки
        $filename = './class/'.$class.'.php';
        if(file_exists()) require_once($filename);
    }
    

    By default, index.php contains:
    require_once 'common.php';
    //
    // Зарегистрируем наш основной автозагрузчик
    spl_autoload_register('mainAutoload');
    //
    // Вызовем нашу функцию вызова модулей
    start_module();
    


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

    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 soul not from soul_basic , and have functionality implemented in 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. Therefore, we create our own soul class. To do this, we modify the index.php file, for example like this:

    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 and accordingly 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. It's just that I separate the church as faith and the church as business. And I don’t think laughing with business is a sin. Although my friends and pals, priests from different faiths do not agree with me ...

    Also popular now: