I have inherited a project in bad conditions that contains the following class and I need your help to improve it, the truth is I don't know if it is correctly optimized or if it has security problems or if it can be simplified or refactored to mitigate some overload / overheating . I can't afford to scrap the entire project because of this class.
php v7.4
I proceed to explain what the class does, This class has 3 main objectives related to its sole responsibility:
responsibility: it is a bridge to the implementation of procedural and simple classes.
To achieve responsibility, 3 objectives are implemented:
- Provide Access to prosedural functions by associating to a Generic class.
- Extract from a directory the php files that correspond to the procedural libraries (where are the functions).
- implement the magic method
__call
andcall_user_func_array
to facilitate the above common goals
Functional code example:
index.php
<?php
require_once 'function_wrapper.php';
class Main
{
public static $funcObj = null;
public function run()
{
$wrapper = new functionWrapper();
$wrapper->proceduralFunctionLoader();
echo '<pre>';
echo var_dump(self::$funcObj['TEST']);
echo '</pre>';
echo '<br>';
self::$funcObj['TEST']->testFoo();
}
}
$main = new Main();
$main->run();
function_wrapper.php
<?php
class functionWrapper
{
public function proceduralFunctionLoader()
{
$libpath = $_SERVER["DOCUMENT_ROOT"].'lib/';
$files = array_diff(scandir($libpath, 1), ['..', '.']);
$functionList = [];
if (!empty($files)) {
Main::$funcObj['TEST'] = [];
foreach ($files as $key => $name) {
if (strpos($name, 'lib.') !== false) {
$classDir = $libpath.$name;
require_once $classDir;
$functionList[$name] = $this->getFunctionsInFile($classDir);
}
}
Main::$funcObj['TEST'] = $this;
}
}
public function getFunctionsInFile($classDir)
{
$source = file_get_contents($classDir);
$tokens = token_get_all($source);
$functions = [];
$nextStringIsFunc = false;
$inClass = false;
$bracesCount = 0;
foreach ($tokens as $token) {
switch ($token[0]) {
case T_CLASS:
$inClass = true;
break;
case T_FUNCTION:
if (!$inClass) {
$nextStringIsFunc = true;
}
break;
case T_STRING:
if ($nextStringIsFunc) {
$nextStringIsFunc = false;
$functions[] = $token[1];
}
break;
case '(':
case ';':
$nextStringIsFunc = false;
break;
case '{':
if ($inClass) {
++$bracesCount;
}
break;
case '}':
if ($inClass) {
--$bracesCount;
if (0 === $bracesCount) {
$inClass = false;
}
}
break;
}
}
return $functions;
}
public function __call($functionName, $args)
{
try {
$result = null;
if (function_exists($functionName)) {
$result = call_user_func_array($functionName, $args);
}
if (null === $result) {
throw new Exception('A Function that does not exist has been Invoked in the System: '.$functionName.'. <br>');
}
return $result;
} catch (Exception $e) {
echo '<pre>';
echo var_dump($e);
echo '</pre>';
exit();
}
}
}
/lib directory have 2 files inside:
lib.test.php
<?php
function testFoo2()
{
echo '<h1>Hello World!!!</h1>';
}
lib.test2.php
<?php
function testFoo()
{
Main::$funcObj['TEST']->testFoo2();
return true;
}
I find one additional problems:
procedural script is forced to return true or any data; if it return nothing or false; trow error like call_user_func_array
error documentation.
if i try implement a validator (expected to return true or false); how can i differentiate if the false return is equivalent to an error or the validation (function) returns false?
$funcObj
static variable is weird, but I guess it's only there for testing purposes? If it is, it should have been removed for this question. \$\endgroup\$