Some time ago I have been developing on a platform that, although it is functional, they leave me negative comments and opinions about the Architecture/Structure/design pattern/anti-design pattern, because it is outdated, I have not even been able to find which pattern they used.
I have done some extensive research and both composer and other frameworks use class loaders.
Some of these loaders use spl_autoload_#######
, in their architecture; with the idea that the developer uses namespaces or class instances like:
<?php
class Foo {
public $aMemberVar = 'aMemberVar Member Variable';
public $aFuncName = 'aMemberFunc';
function aMemberFunc() {
print 'Inside `aMemberFunc()`';
}
}
$foo = new Foo;
?>
for later:
<?php
$element = 'aMemberVar';
print $foo->$element; // prints "aMemberVar Member Variable"
?>
the criteria of the Autoload of the Composer or framewrok is in charge of carrying out the include_once
or require_once
, spl_autoload_#######
of the necessary file where the class or function is located; this also allows you to run standalone PHP files as long as you have the USE NAMESPACE/NAMESPACE
.
spl_autoload_register(function ($clase) {
include 'clases/' . $clase . '.clase.php';
});
either
namespace Foobar;
class Foo {
static public function test($nombre) {
print '[['. $nombre .']]';
}
}
spl_autoload_register(__NAMESPACE__ .'\Foo::test'); // A partir de PHP 5.3.0
new ClaseInexistente;
Mistake
[[Foobar\NonexistentClass]] Fatal error: Class 'Foobar\NonexistentClass' not found in ...
So, in the code I'm working on, they do something completely different:
The file index.php
that acquires the system constants through a requiere_once
, also has a Parent class CoreApp
that is always the one that receives everything: initial access, Requests: Get, POST, etc.
<?php
//require_once 'configs/const/loader.php'; // Acceso a las constantes del sistema
//se agrego las definiciones para hacer que el codigo sea ejecutable.
if (!defined('FILEROOT')) {
define('FILEROOT', $_SERVER['DOCUMENT_ROOT']);
}
$paths = [
'CLASSEXT' => FILEROOT.'/apps/class/ext/',
'CLASSMVC' => FILEROOT.'/apps/class/mvc/',
'CLASSGEN' => FILEROOT.'/apps/class/gen/',
'CLASSCORE' => FILEROOT.'/apps/core/',
'TPLSTATIC' => FILEROOT.'/html/static/',
'TPLDASH' => FILEROOT.'/html/dash/',
'TPLSITE' => FILEROOT.'/html/site/',
'TPLSTATUS' => FILEROOT.'/html/status/',
'TPLSTORE' => FILEROOT.'/html/store/'
];
if (!defined('PATHS')) {
define('PATHS', $paths);
}
class CoreApp
{
public static $oclass = null;
// propiedad de la clase en donde se Guardaran las clases que se heredaran en las sub-capas
public static $ovars = null;
// propiedad de la clase en donde se Guardaran las variables que se heredaran en las sub-capas
private static $instance = null;
public static function _getInstance()
{
if (!self::$instance instanceof self) {
self::$instance = new self;
}
return self::$instance;
}
public function goCoreApp()
{
$this->popClass();
echo 'hello World';
//self::$oclass['GEN']['APP']->runInit();
//self::$oclass['MVC']['CONTROLLER']->runController();
//self::$oclass['GEN']['APP']->runClose();
}
private function popClass()
{
//se llama al archivo y la funcion que se encargara de poblar la porpiedad $oclass
require_once FILEROOT.'/apps/class-manager.php';
ClassManager::_getInstance()->LoadClass();
}
}
ob_start();
CoreApp::_getInstance()->goCoreApp();
Then in the next layer it calls ClassManager::_getInstance()->LoadClass();
which is a class loader which is going to populate the property CoreApp::$oclass
that is executed in the following way:
<?php
class ClassManager
{
private static $instance = null;
public function LoadClass()
{
$classPaths = [
'GEN' => PATHS['CLASSGEN'],
'MVC' => PATHS['CLASSMVC']
];
$this->requireClassFile(PATHS['CLASSEXT'].'vendor/autoload.php');
$this->ClassLoader($classPaths);
}
public static function _getInstance()
{
if (!self::$instance instanceof self) {
self::$instance = new self;
}
return self::$instance;
}
private function CheckFileIntegrity($file)
{
$dl = ['st' => false, 'msg' => ''];
$smg1 = '';
$fileR = file($file);
$c = 1;
foreach ($fileR as $line) {
if (!strlen(trim($line))) {
$smg1 .= 'Incorrect space/Linebreak found file: '.$file.EOL_SYS.'Line: '.$c.EOL_SYS;
$dl['st'] = true;
++$c;
} else {
break;
}
}
$dl['msg'] = $smg1;
return $dl;
}
private function ClassLoader($classPaths)
{
foreach ($classPaths as $key => $path) {
$dl = [];
$class_store = &CoreApp::$oclass[$key];
$files = array_diff(
scandir($path, 1),
['..', '.']
);
foreach ($files as $key => $name) {
if (strpos($name, 'class-') !== false) {
$fl_dir = $path.$name;
$dl = $this->CheckFileIntegrity($fl_dir);
if (!$dl['st']) {
$this->requireClassFile($fl_dir);
$name = explode("-", preg_replace('#\.php#', '', $name));
foreach ($name as $key => $cl_name) {
$name[$key] = ucfirst(strtolower($cl_name));
}
$new_name_class = implode('', $name);
$instance_class = strtoupper(
preg_replace('#\Class#', '', $new_name_class)
);
$new_name_class .= 'Manager';
$class_store[$instance_class] = $new_name_class::_getInstance();
} else {
echo
'PHP files cannot have line breaks at the beginning '.
'or end.<br> There is a problem with this file: <b> '.
PATHS['CLASSGEN'].$name.'</b> <br> <br>'.
$dl['msg'];
die;
}
}
}
}
}
private function requireClassFile($file)
{
return require_once $file;
}
}
Dependency: For this Script to work, it is necessary to create a folder in root with the following structure:
/apps/class/ext/
#where all the composer installation and external libraries accessible by composer autoload will be placed.
/apps/class/gen/
#where all the generic classes will be placed.
/apps/class/mvc/
# where all the mvc classes will be placed.
Example of a Generic Class and an MVC:
class-test.php //class name must start with
class-
class ClassTestManager
{
private static $instance = null;
public static function _getInstance()
{
if (!self::$instance instanceof self) {
self::$instance = new self;
}
return self::$instance;
}
public function test()
{
echo 'hello world';
}
}
In summary:
for the end they have the property CoreApp::$oclass
with all the classes pre-instantiated. once this is done from any layer you can call a function as follows:
self::$oclass['GEN']['TEST']->test();
self::$oclass['GEN']['APP']->runInit();
self::$oclass['MVC']['CONTROLLER']->runController();
self::$oclass['GEN']['APP']->runClose();
either
CoreApp::$oclass['GEN']['VARS']->expVariable(true, true, false, true, CoreApp::$ovars, [$stuser, $isdata, $isdatatype, $iscron, $iswser])
does not require the use of USE NAMESPACE/NAMESPACE
or the use of Instancias
; neither of extender
.
But I've never had a canonical answer as to why?
Project Link on Github
this is a project with little documentation in the code, Questions:
- What pattern is it?
- What are the weaknesses of this Architecture/Structure/design pattern/anti design pattern or the logic of using an Object or property to inherit pre-initialized Classes and Functions?
- What errors can I be making, that the application stops working or is it an exploit?
- What improvements (re-factory) can the class code have
class ClassManager
to make it more efficient?
Update Comments / Clarifications
- They tell me that there is a weakness in pre-initializing classes that are not used because they read from disk and save data in ram memory and can impact the speed of the system, for example knowing the server time for any use within the system.
Ans: The truth is that it is only read from disk once, and it is also saved once in ram, and the resource is saved in the object/Property CoreApp::$oclass
which provides RAM access at runtime to any Class/function without need to resort to SPL_AUTOLo-
... It is or is not a Weakness; I would need to test the scalability right.
Ans.: It is not a defined pattern; what is implemented is an "orthodox" pattern from the time when namespaces did not yet exist and is a mix between factory, construction and Singleton. It is not badly planned, it is manageable but not the best option, among the existing ones (canonically it does not even have this pattern registered).
Ans.: the only Appreciable Weakness is; its limitations mainly with the software traceability of the code since the Symbolic Methods have these problems and an indexing by text search must be resorted to, this is present only in ST3; but VScode and phpStorm don't have proper/native support.
Example:
Ans.: As I said at the beginning, the only exploit you can have depends on the version of php and the errors made by the programmer... there is no Exploit if a security layer is presented correctly.
class ClassManager
to make it more efficient?Ans.: Normally, all projects with these characteristics tend to migrate to design patterns that employ the use of namespace and resource control based on a logic established in common among developers, since it does not respond to any development framework structure.
Currently the Development is being refactored and migrated to this last mentioned point.