Layered Architecture and Class Management (no framework)

0

Updated

I have a memory overflow problem in a layered architecture, the development has been going on for several years and they have tried to optimize some parts but the main problem lies in the Instances of the classes in the sub-layers

I list it in the following way so that we have a general idea of how the structure is:

Layer1

File Index.php

require_once "control/class.Main.php"; #hacemos el require once a la libreria Main de nuestra APP
$WebAPP = new Class_MAIN();
$WebAPP->Main(); #llamamos a la Funcion Main

Capa2

Main.php File

class Class_MAIN {
    public function __construct() {
        require_once 'control/config/config.externas.php'; #este archivo realiza un include de las librerias externas
        require_once 'control/config/config.genericas.php'; #este archivo realiza un include de las librerias genericas
        require_once 'control/config/config.modulos.php'; #este archivo realiza un include de las modulares
        //el archivo config.modulos.php se encarga de hacer include de otros archivo 
        //en este caso class.content.php y class.menu.php

        #Instanciamos las clases necesarias

        $this->CONTENTMANAGER  = new Class_ContentManager(); #el contenido a Mostrar por pantalla.

    }
    #llamada a la clase que genera el Display
    public function Main() {
        $this->CONTENTMANAGER->Gen_Display(); # Genera el Codigo html de la pagina.
    }
}

Capa3

class.content.php file in layer 3 we can locate the CONTENTMANAGER class mentioned in layer 2, this initializes classes that were included (require_once) in layer 2. the GetMenuSide function raises some files by require_once that are actually html. as we see in the constructor for the first time we see Class Class_BDManager that is intact

    class Class_ContentManager{
        public function __construct() {
            #Llamamos a los archivos que se requieren para el funcionamiento de la pagina
            $this->MENUMANAGER    = new Class_MenuManager();
            $this->FORMMANAGER    = new Class_FormManager();
            $this->PROCESSMANAGER = new Class_ProcessManager();
            $this->MODALSMANAGER  = new Class_ModalManager();
            $this->DBMANAGER = new Class_BDManager();
        }
        function GetMenuSide() {
            require_once "sources/tpl/navside/start.side.php";
            $this->MENUMANAGER->MenuSideManager();
            require_once "sources/tpl/navside/end.side.php";
        }
    }

Capa4

class.menu.php file     we can say that in this layer is the MenuSideManager class mentioned in layer 3 and that in turn initializes classes again $ this- > DBMANAGER = new Class_BDManager (); that were included in layer 2

class Class_MenuManager{
        public function __construct() {
            $this->DBMANAGER = new Class_BDManager();
        }
        function MenuSideManager(){
            #Consulta permisos del menu
        }
    }

if we see $ this-> DBMANAGER = new Class_BDManager (); is Installed for some reason in 2 layers 3 and 4, and as far as I understand the system does the same in layer 5, 6, 7, 8; I also observe that not only is it a class, let's say that this happens with classes by blocks:

External Classes

Generic classes

Classes to generate Views (Lists Etc)

only Generic classes perform these call intancias, for each class file in the module section that would be layer 6:

$this->COOKIESMANAGER  = new Class_CookiesManager();
$this->CRIPMANAGER     = new Class_CripManager();
$this->DATEMANAGER     = new Class_DateManager();
$this->DBMANAGER       = new Class_BDManager();
$this->ERRORMANAGER    = new Class_ErrorManager();
$this->FILEMANAGER     = new Class_FileManager();
$this->HTTPDATAMANAGER = new Class_HTTPDataManager();
$this->LOGSMANAGER     = new Class_LogsManager();
$this->MEMORYMANAGER   = new Class_MemoryManager();
$this->URLMANAGER      = new Class_UrlManager();
$this->USERMANAGER     = new Class_UserManager();
$this->CRUDMANAGER     = new Class_CrudManager();# permisos
$this->SESSIONMANAGER  = new Class_SessionManager();
$this->EMAILMANAGER    = new Class_EmailManager();
$this->ORDERMANAGER    = new Class_OrderManager();
$this->VARMANAGER      = new Class_VarManager();
$this->FTPMANAGER      = new Class_FtpManager();

the part of the require_once is done dynamically with the following script:

<?php
class Class_MAIN{
    protected $ObjClass;
    protected $ObjNameclass;
    public function __construct() {
        require_once 'const/Constant.php';
        require_once 'class/ClassManager.php';
        $this->AUTOLOAD = new ClassManager();
        $this->ObjClass = [];
        $this->ObjClass = $this->AUTOLOAD->LoadClass($this->ObjClass);
        foreach ($this->ObjClass as $key => $Class) {
            require_once $Class;
        }
        #aqui se instanciaran solo  las clases necesarias
    }
    public function Main() {

    #aqui iran las funciones necesarias


    }
}
?>

The main idea or objective is:

inherit in some way the instantiation of the classes through a public object that can be accessed from any of the sub-layers and make direct use of the functions that are in the generic classes, an example of a query based on serious data something like this:

#$this->ObjNameclass['DBManager'] puede ser la propiedad declara o objeto eredado

$this->$this->ObjNameclass['DBManager']->BDQuery(datos);

I know that they will tell me how best to use a framework but that would indicate that I must complete a development that has been going on for 6 years, and also many files to edit for each layer, I would look for ways to edit these files as little as possible. I'm looking for a solution based on this same architecture.

I will be doing other updates with more details implementing the responses of the partners.

    
asked by Francisco Núñez 20.10.2017 в 00:39
source

3 answers

3

First of all, what you have is a framework, but you should establish a starting point for the application and load the modules inheriting the previous functionality, I would start by defining a general class that encompasses them all:

class APP {
    // aquí deberías incluir todas las propiedades como protegidas,
    // así únicamente una clase que herede de APP podrá obtener su
    // contenido y podría modificarlo (todas las clases deberían
    // heredar de APP, por lo que no tendrías inconvenientes de 
    // acceso, pero lo restringes a tu framework)
    protected CONTENTMANAGER;
    protected MENUMANAGER;
    protected FORMMANAGER;
    protected PROCESSMANAGER;
    protected MODALSMANAGER;
    protected DBMANAGER;

    public function  __construct() {
        // requerir sólo lo necesario en cada caso
        require_once 'control/config/config.externas.php';
        require_once 'control/config/config.genericas.php';
        require_once 'control/config/config.modulos.php';

        // no instanciar nada aquí

    }
}

And then, make each part of the system inherit from the base of it:

class Class_MAIN extends APP {
    public function __construct(){
        // Llamar al constructor padre para que genere los require
        parent::__construct();

        $this->CONTENTMANAGER  = new Class_ContentManager();
    }

    public function Main(){
        $this->CONTENTMANAGER->Gen_Display($USERLoged, $DTACheck);
    }
}

If you need to load modules or initialize classes before using any part of the system, what you have to do is load the constructor of the class from which it is extended, in this case it would be APP and then load the modules or instantiate properties:

class Class_ContentManager extends APP {
    public function __construct() {
        // Llamar al constructor padre para que genere los require
        parent::__construct();

        // Poblar las propiedades requeridas para el funcionamiento de la página
        $this->MENUMANAGER    = new Class_MenuManager();
        $this->FORMMANAGER    = new Class_FormManager();
        $this->PROCESSMANAGER = new Class_ProcessManager();
        $this->MODALSMANAGER  = new Class_ModalManager();
        $this->DBMANAGER      = new Class_BDManager();
    }

    function GetMenuSide() {
            require_once "sources/tpl/navside/start.side.php";
            $this->MENUMANAGER->MenuSideManager();
            require_once "sources/tpl/navside/end.side.php";
    }
}

In this way, you avoid requesting and instantiating the same class twice and you can use them in all subsequent layers.

Edit:

If you want some functionality to be available for all classes that inherit from APP , you just have to include that functionality in APP , for example, if you want to have the database functionality instantiated , the class APP would be as follows:

class APP {
    // aquí deberías incluir todas las propiedades como protegidas,
    // así únicamente una clase que herede de APP podrá obtener su
    // contenido y podría modificarlo (todas las clases deberían
    // heredar de APP, por lo que no tendrías inconvenientes de 
    // acceso, pero lo restringes a tu framework)
    protected CONTENTMANAGER;
    protected MENUMANAGER;
    protected FORMMANAGER;
    protected PROCESSMANAGER;
    protected MODALSMANAGER;
    protected DBMANAGER;

    public function  __construct() {
        // requerir sólo lo necesario en cada caso
        require_once 'control/config/config.externas.php';
        require_once 'control/config/config.genericas.php';
        require_once 'control/config/config.modulos.php';

        // instanciar sólo lo necesario
        $this->DBMANAGER = new Class_BDManager();
    }
}

And, subsequently, remove all instances in the constructors of $this->DBMANAGER to avoid recharge in each layer.

Update - Final Solution

Viewing your code in detail and analyzing what it does and your explanations, I think what you need is a code like the following:

// los objetos creados, serán globales
$Objects = [];

// clase que maneja las clases ;)
class ClassManager{

    // Función de carga de clases, es estática para evitar tener que 
    // instanciar el manejador de clases, agrega la clase al arreglo
    // de objetos globales y retorna la instancia generada
    public static function LoadClass($clase, $nueva_instancia = false){
        // Obtengo los objetos globales
        global $Objects;

        // si no existe el objeto de esta clase o existe pero
        // se requiere una nueva instancia
        if(!isset($Objects[$clase]) || 
           (isset($Objects[$clase]) && $nueva_instancia == true)) {

            // cargo el archivo
            require_once "class/$clase.php";

            // instancio
            $instancia = new $clase();

            // agrego la instancia al arreglo de objetos globales
            $Objects[$clase] = $instancia;
        } else {
            // sino, obtengo la instancia del arreglo de objetos globales
            $instancia = $Objects[$clase];
        }

        // y retorno la instancia
        return $instancia;
    }
}

what you will have to do next is, anywhere in your code that you need to instantiate (or get an instance, depending on the case) will be:

ClassManager::LoadClass('DBManager')->BDQuery(datos);

If you need to reload the instance, you should set the second LoadClass parameter to true:

ClassManager::LoadClass('ErrorManager', true)->ShowError('Lo que sea');

I hope it serves you.

    
answered by 23.10.2017 / 22:07
source
2

To avoid making the include and avoid including the classes themselves you can use class_exists before defining the class in each class definition file in that way even if the method calls the include class not will be defined again.

if (! class_exists('MyClass')) {

    class MyClass {

    }

}

To avoid defining the same variable again and have access to it.

protected static DBMANAGER = null;

or

public static DBMANAGER = null;

and use it like this:

public function __construct() {

    if (! self::DBMANAGER instanceof Class_BDManager) {
        self::DBMANAGER = new Class_BDManager();
    }
}

To instantiate DBMANAGER anywhere you can make the property public and do:

if (! Class_MenuManager::DBMANAGER instanceof Class_BDManager) {
   Class_MenuManager::DBMANAGER = new Class_BDManager();
}

or

You can make the protected property and make a public setter method:

public static setDbManager (Class_BDManager $db) {

    if (! Class_MenuManager::DBMANAGER instanceof Class_BDManager) {
       Class_MenuManager::DBMANAGER = $db;
    }

}

or

public static setDbManager () {

    if (! Class_MenuManager::DBMANAGER instanceof Class_BDManager) {
       Class_MenuManager::DBMANAGER = new Class_BDManager();
    }

}

Your class definitions would look like this:

if (! class_exists('Class_MenuManager') ) {

    class Class_MenuManager{

        private static DBMANAGER = null;

        public function __construct() {

        }

        function MenuSideManager(){
            #Consulta permisos del menu
        }

        public static setDbManager () {

            if (! self::DBMANAGER instanceof Class_BDManager) {
                self::DBMANAGER = new Class_BDManager();
            }

        }

         public static getDbManager () {

            self::setDbManager();
            return self::DBMANAGER;
        }

    }
}

to get DBMANAGER from anywhere $db = Class_MenuManager::getDbManager(); you will always get the same object. but as you remove it from the constructor so that it is not defined if you are not going to use it and getDbManager makes sure to define it before using it so you will not have problem

    
answered by 23.10.2017 в 18:25
-1

Good to everyone after drilling into the few neurons that alcoholism has left me with drugs and women ... I've managed to find the answer:

first of all the creation of an object that can contain the classes and inherit them in all the functions that each layer from layer 2 to 5

<?php
class Class_MAIN{
    public $ObjClass;
    public $ObjClassInst;
    public function __construct() {
        require_once 'const/Constant.php';
        require_once 'class/ClassManager.php';
        $this->AUTOLOAD = new ClassManager();
        $this->ObjClass = [];
        $this->ObjClass = $this->AUTOLOAD->LoadClass($this->ObjClass);
        foreach ($this->ObjClass as $key => $Class) {
            require_once $Class;
        }
        $this->ObjClassInst = [];
        $this->ObjClassInst = $this->AUTOLOAD->ClassPack($this->ObjClassInst);
    }
    public function Main() {
        $this->ObjClassInst['Generic']['CAPA3MANAGER'] ->pruebacapa3();
    }
}
?>

This works correctly and generates an object in the class index. It saves me every Instanced Class:

array(1) { 
    ["Generic"]=> array(3) { 
        ["CAPA5MANAGER"]=> object(Class_Capa5Manager)#3 (0) { } 
        ["CAPA4MANAGER"]=> object(Class_Capa4Manager)#4 (0) { } 
        ["CAPA3MANAGER"]=> object(Class_Capa3Manager)#5 (0) { } 
    } 
}

The library that generates this object, which makes the require_once of each class according to the directory and which in turn stores the intancias in the following ClassManager object:

<?php
class ClassManager {
    public function LoadClassExternal(&$ObjClass) {
        $External = scandir(EXTCLASS, 1); # Directorio de archivos
        foreach ($External as $key => $name) {
            if (strpos($name, 'class.') !== false) {
                #require_once EXTCLASS.''.
                $ObjClass[$name] = EXTCLASS . $name;
            } elseif(strpos($name, 'phpMailer') !== false) {
                $ObjClass[$name] = EXTCLASS . $name .'/PHPMailerAutoload.php';
            } elseif(strpos($name, 'html2pdf') !== false) {
                $ObjClass[$name] = EXTCLASS . $name .'/html2pdf.class.php';
            } elseif(strpos($name, 'fpdf') !== false) {
                $ObjClass[$name] = EXTCLASS . $name .'/fpdf.php';
            }
        }
        return $ObjClass;
    }
    public function LoadClassGeneric(&$ObjClass) {
        $Generic = scandir(GENCLASS, 1); # Directorio de archivos
        foreach ($Generic as $key => $name) {
            if (strpos($name, 'class.') !== false) {
                $ObjClass[$name] = GENCLASS . $name;
            }
        }
        return $ObjClass;
    }
    public function LoadClassCRON(&$ObjClass) {
        $Cron = scandir(CRONCLASS, 1); # Directorio de archivos
        foreach ($Cron as $key => $name) {
            if (strpos($name, 'class.') !== false) {
                $ObjClass[$name] = CRONCLASS . $name;
            }
        }
        return $ObjClass;
    }
    public function LoadClassMVC(&$ObjClass) {
        $MVC = scandir(MVCCLASS, 1); # Directorio de archivos
        foreach ($MVC as $key => $name) {
            if (strpos($name, 'class.') !== false) {
                $ObjClass[$name] = MVCCLASS . $name;
            }
        }
        return $ObjClass;
    }
    public function LoadClassCORE(&$ObjClass) {
        $CoreD = scandir(CORECLASS, 1); # Directorio de archivos
        foreach ($CoreD as $key => $nameD) {
            if (strpos($nameD, 'doc') !== false) {
                $CoreF = scandir(CORECLASS.$nameD.'/', 1); # Directorio de archivos
                foreach ($CoreF as $key => $nameF) {
                    if (strpos($nameF, 'doc') !== false) {
                        $ObjClass[$nameF] = CORECLASS.$nameD.'/' . $nameF;
                    }
                }
            }
            if (strpos($nameD, 'form') !== false) {
                $CoreF = scandir(CORECLASS.$nameD.'/', 1); # Directorio de archivos
                foreach ($CoreF as $key => $nameF) {
                    if (strpos($nameF, 'form') !== false) {
                        $ObjClass[$nameF] = CORECLASS.$nameD.'/' . $nameF;
                    }
                }
            }
            if (strpos($nameD, 'list') !== false) {
                $CoreF = scandir(CORECLASS.$nameD.'/', 1); # Directorio de archivos
                foreach ($CoreF as $key => $nameF) {
                    if (strpos($nameF, 'list') !== false) {
                        $ObjClass[$nameF] = CORECLASS.$nameD.'/' . $nameF;
                    }
                }
            }
            if (strpos($nameD, 'modal') !== false) {
                $CoreF = scandir(CORECLASS.$nameD.'/', 1); # Directorio de archivos
                foreach ($CoreF as $key => $nameF) {
                    if (strpos($nameF, 'modal') !== false) {
                        $ObjClass[$nameF] = CORECLASS.$nameD.'/' . $nameF;
                    }
                }
            }
            if (strpos($nameD, 'not') !== false) {
                $CoreF = scandir(CORECLASS.$nameD.'/', 1); # Directorio de archivos
                foreach ($CoreF as $key => $nameF) {
                    if (strpos($nameF, 'not') !== false) {
                        $ObjClass[$nameF] = CORECLASS.$nameD.'/' . $nameF;
                    }
                }
            }
            if (strpos($nameD, 'process') !== false) {
                $CoreF = scandir(CORECLASS.$nameD.'/', 1); # Directorio de archivos
                foreach ($CoreF as $key => $nameF) {
                    if (strpos($nameF, 'process') !== false) {
                        $ObjClass[$nameF] = CORECLASS.$nameD.'/' . $nameF;
                    }
                }
            }
        }
        return $ObjClass;
    }
    public function LoadClass(&$ObjClass) {
        #require files
        $this->LoadClassExternal($ObjClass);
        $this->LoadClassGeneric($ObjClass);
        $this->LoadClassCRON($ObjClass);
        $this->LoadClassMVC($ObjClass);
        $this->LoadClassCORE($ObjClass);
        return $ObjClass;
    }
    public function ClassPackExternal(&$ObjClassInst) {
        return $ObjClassInst;
    }
    #Esta Seccion es la que instancia las Clases
    public function ClassPackGeneric(&$ObjClassInst) {
        $Generic = scandir(GENCLASS, 1); # Directorio de archivos
        foreach ($Generic as $key => $name) {
            if (strpos($name, 'class.') !== false) {
                $name=preg_replace('#\.php#', '', $name);
                $names=explode(".", $name);
                foreach ($names as $key => $namesr) {
                    $names[$key]=ucfirst(strtolower($namesr));
                }
                $name=implode('_', $names);
                $NamesClass = $name.'Manager';
                $InstanceClass = strtoupper(preg_replace('#\Class_#', '', $NamesClass));
                #$ObjClassInst['Generic'][$InstanceClass] = $NamesClass;
                $ObjClassInst['Generic'][$InstanceClass] = $this->$InstanceClass= new $NamesClass();
            }
        }
        return $ObjClassInst;
    }
    public function ClassPackCRON(&$ObjClassInst) {
        return $ObjClassInst;
    }
    public function ClassPackMVC(&$ObjClassInst) {
        return $ObjClassInst;
    }
    public function ClassPackCORE(&$ObjClassInst) {
        return $ObjClassInst;
    }
    public function ClassPack(&$ObjClassInst){
        #require files
        $this->ClassPackExternal($ObjClassInst);
        $this->ClassPackGeneric($ObjClassInst);
        $this->ClassPackCRON($ObjClassInst);
        $this->ClassPackMVC($ObjClassInst);
        $this->ClassPackCORE($ObjClassInst);
        return $ObjClassInst;
    }
}
?>

I still can not make the object or property public on all layers but log an object that packs the intancias of each group of classes

New POST: Link

    
answered by 24.10.2017 в 23:54