📜 ⬆️ ⬇️

Work with modules

Task:
Use a class in which you can add new methods of exposure so that you can use them later. In this case, separate these methods by different files.
Imagine a spacecraft in which are used:
a) movement methods associated with the engine
b) energy charging methods associated with its solar panels
c) etc.

There are options:
1) Creating variables in the object and initializing them through __construct, as new classes.
But, when creating each new object, we get a decrease in performance and constant modification of the class (which may complicate the work of several programmers).
2) Work through functions __ call, __ get, __ set.
3-10 times slower operation of these functions. Especially when calling call_user_func_array with parameters.

I offer my version.
Fast, optimized, but there is a small difficulty in debugging.
')
In this habratopic I will touch on the topics:
1. Overloading
2. Acceleration of loading modules. Combining modules.
3. Optimization

Alternative approach


We can combine all modules into one file, while merging the same classes into one.

For this, I wrote a module that I will analyze a little later.

To work with the module, it is used (similar to the Singleton pattern) - the mods function. It initializes the module and looks like this:
/**
* modules
*
* @return <modules> -
*/

function mods(){
static $mod;
if (!isset($mod))
$mod= new modules;
return $mod;
}

For operation of the merging module, two cache files are used.

One of them is necessary in order to store all the plug-in classes (in the serialize form). From them, with the help of the __autoload function, the necessary ones are selected that are necessary for work.
The second file is all the necessary modules merged together in a php file. It is just being loaded, instead of all modules.

Initialization of these two files occurs at the beginning, when the module is initialized:
mods()->cache( 'cache.data' )
->phpcache( 'cache.php' );
Files can be set different. I, for example, on different pages of the site (on which different modules are used), use different phpcache files.

By combining all the files into one, downloading files is faster. (plus, I advise you to install eAccelerator for yourself, so that the files load instantly)

But, it is also necessary to add modules that are loaded into the system (this works as a simple include):
mods()->include_php( 'modules/mod1.php' );
And at the end convert the modules into one file, loading it:
mods()->include_modules();

An example of working with modules

// ( )
define ( 'PHP_DEBUG_MODE' ,1);

// php-
mods()->cache( 'cache.file' )
->phpcache( 'cache.php' );

//
if (PHP_DEBUG_MODE==1){
$files = glob($moddir. '/*.inc' );
foreach ($files as $file){
mods()->include_php($file);
}

//
mods()->include_modules();

I want to draw attention to define PHP_DEBUG_MODE . There is no need to study all modules to check changes every time. Therefore, when the modules inside will not change, you can disable this check (by equating PHP_DEBUG_MODE to 0), leaving only the connection of the ready cache-php module (include_modules) containing all the necessary classes.

What happens

1) Merging classes.
//file_A.php
class A{
public $start;

function start(){
$ this ->start=1;
}
}
//file_B.php
class A{
private $stop;

function stop(){
$ this ->stop=1;
}
}
Result:
//result_cache.php
class A{
public $start;
private $stop;

function start(){
$ this ->start=1;
}

function stop(){
$ this ->stop=1;
}
}


2) Merging functions within classes
//file_A.php
class A{
public $start;

function __construct(){
$ this ->start=1;
}
}
//file_B.php
class A{
public $stop;

function __construct(){
$ this ->stop=1;
}
}
Result:
//result_cache.php
class A{
public $stop;
public $start;

function __construct(){
$ this ->stop=1;
$ this ->start=1;
}
}


Implementation


/**
*
*
* @param <string> $class -
*/

function __autoload($ class ){
mods()->putclass($ class );
}

/**
* modules
*
* @return <modules> -
*/

function mods(){
static $mod;
if (!isset($mod))
$mod= new modules;
return $mod;
}

class modules{
private $dataclass=array();
private $datacache_date=0;
private $datacache_name= null ;
private $classesfile= null ;
private $classesfiledate=0;
private $classesincluded= false ;

/**
*
*
* @param <string> $file - +
*/

public function cache($file){
$ this ->datacache_name=$file;
if (file_exists($file)){
$ this ->datacache_date=filemtime($file);
}
return $ this ;
}

/**
* php-
*
* @param <string> $file - +
*/

public function phpcache($file){
$ this ->classesfile=$file;
if (file_exists($file))
$ this ->classesfiledate=filemtime($file);
}

/**
*
*
* @param <string> $file -
*/

public function include_php($file){
if (!file_exists($file)){
$ this ->fatalerror( 'no include file \'<b>' .$file. '</b>\'' );
}

if ($ this ->datacache_date<filemtime($file)){
$ this ->loadcachedata();
$ this ->removefile($file);
$ this ->parsephp(file_get_contents($file),$file);
file_put_contents($ this ->datacache_name,serialize($ this ->dataclass));
if ($ this ->classesfiledate!=0){
unlink($ this ->classesfile);
$ this ->classesfiledate=0;
}
}elseif ($ this ->classesfiledate!=0 && $ this ->classesfiledate<filemtime($file)){
unlink($ this ->classesfile);
$ this ->classesfiledate=0;
}

return $ this ;
}

/**
*
*/

public function include_modules(){
if (!$ this ->classesincluded){
if (!file_exists($ this ->classesfile)){
$ this ->loadcachedata();
file_put_contents($ this ->classesfile, "<?\n" .$ this ->printclass( '' ). "\n?>" );
}
include_once($ this ->classesfile);
$ this ->classesincluded= true ;
}
}

/**
*
*
* @param <string> $file -
*/

private function removefile($file){
foreach ($ this ->dataclass as $key=>&$ class ){
foreach ($ class [0] as $name=>$vars)
if ($name==$file)
unset($ class [0][$name]);
foreach ($ class [1] as $fk=>&$ function ){
foreach ($ function as $name=>$vars)
if ($name==$file)
unset($ function [$name]);
if ($ function ==array())
unset($ class [1][$fk]);
}

if ($ class [0]==array() && $ class [1]==array())
unset($ this ->dataclass[$key]);
}
}

/**
* PHP-
*
* @param <string> $class -
* @return <string> -
*/

private function printclass($ class = '' ){
if ($ class == '' ){
$ string =implode( "\n" ,$ this ->dataclass[ '' ][0]);
foreach ($ this ->dataclass[ '' ][1] as $fname=>$ function )
$ string .= "\nfunction " .$fname. "{\n" .implode( "\n" ,$ function ). "\n}" ;
return $ string ;
}

foreach ($ this ->dataclass as $classname=>$data){
$name=preg_split( '/\s/' , $classname);

if ($name[0]==$ class ){
$ string = 'class ' .$classname. '{' .implode( "\n" ,$data[0]);
foreach ($data[1] as $fname=>$ function )
$ string .= "\nfunction " .$fname. "{\n" .implode( "\n" ,$ function ). "\n}" ;

return $ string . '}' ;
}
}
return false ;
}

/**
* cache-
*/

private function loadcachedata(){
if ($ this ->dataclass!=array())
return ;

if (file_exists($ this ->datacache_name))
$ this ->dataclass=unserialize(file_get_contents($ this ->datacache_name));
}

private function classfiles($ class ){
foreach ($ this ->dataclass as $classname=>$data){
$name=preg_split( '/\s/' , $classname);

if ($name[0]==$ class ){
$keys=array();
foreach ($data[1] as $dat)
$keys=array_merge(array_keys($data[0]),$keys);
return implode( ", " ,array_unique(array_merge(array_keys($data[0]),$keys)));
}
}
}


/**
* .
* php-cache .
*
* @param <string> $class -
*/

public function putclass($ class ){
if (!$ this ->classesincluded){
$ this ->includemodules();
if (class_exists($ class , false ))
return ;
}

$ this ->loadcachedata();

if (($evclass=$ this ->printclass($ class ))!== false ){
file_put_contents($ this ->classesfile, "<?\n" .$evclass. "\n?>" ,FILE_APPEND);
chmod($ this ->classesfile,0777);
if (@eval($evclass)=== false ){
$ this ->fatalerror( 'Error in class <b>' .$ class . '</b> in file <b> ' .$ this ->classfiles($ class ). '</b>' );
}
}
}

/**
*
*
* @param <string> $classname -
* @param <array> $class -
* @param <string> $filename - ,
*/

private function mergeclass($classname,$ class ,$filename){
if (!isset($ this ->dataclass[$classname][0][$filename])){
$ this ->dataclass[$classname][0][$filename]= '' ;
}

$ this ->dataclass[$classname][0][$filename].=$ class [0];
if (!isset($ this ->dataclass[$classname][1]))
$ this ->dataclass[$classname][1]=array();

foreach ($ class [1] as $fname=>$ function ){
if (!isset($ this ->dataclass[$classname][1][$fname][$filename]))
$ this ->dataclass[$classname][1][$fname][$filename]= '' ;
$ this ->dataclass[$classname][1][$fname][$filename].=$ function ;
}
}

/**
* php ,
*
* @param <string> $php -
* @param <string> $filename -
*/

private function parsephp($php,$filename){
if (($pos=strpos($php, '<?' ))!== false ){
$pos+=2;
if (strtolower(substr($php,$pos,3))== 'php' )
$pos+=3;
}
if (!preg_match_all( '/((?:[^\'"\/$]|([\'"])(?:\\\\[\s\S]|[\s\S])*\2|\/[^*]|\/\*[\s\S]*\*\/|\$[^;\'"(){}\s]++)*)([{};]|\?>|$|\s(function)\s|\s(class)\s)/DSU' ,$php,$scobe,PREG_SET_ORDER|PREG_OFFSET_CAPTURE,$pos))
return ;

for ($i=0,$j=count($scobe);$i<$j;$i++){
if (isset($scobe[$i][5]) && $scobe[$i][5][0]== 'class' && $i<$j-1 && $scobe[$i+1][3][0]== '{' ){
//is class
$newclass=array( '' ,array());

for ($x=$i+2;$x<$j;$x++){
$test=&$scobe[$x][3][0];

if (isset($scobe[$x][4][0]) && $scobe[$x][4][0]== 'function' && $x<$j-1 && $scobe[$x+1][3][0]== '{' ){

$name=$scobe[$x+1][1][0];
$ function = '' ;
for ($x+=2,$sco=1;$x<$j;$x++){
$test=&$scobe[$x][3][0];
if ($test== '{' )
++$sco;
elseif ($test== '}' )
if (--$sco==0)
break ;
$ function .=$scobe[$x][0][0];
}
if ($x==$j)
$ this ->fatalerror( 'error parsing function' .$name. ' in class <b>' .$scobe[$i+1][1][0]. '</b>, not found }' );

$newclass[1][$name]=$ function ;
}elseif ($test== ';' )
$newclass[0].=$scobe[$x][0][0];
elseif ($test== '}' )
break ;
else $ this ->fatalerror( 'error parsing ' .$test. ' in class <b>' .$scobe[$i+1][1][0]. '</b>' );
}

$ this ->mergeclass($scobe[$i+1][1][0],$newclass,$filename);

$i=$x;
} else {
if ($scobe[$i][3][0]== '?>' )
$ this ->mergeclass( '' ,array($scobe[$i][1][0],array()),$filename);
else
$ this ->mergeclass( '' ,array($scobe[$i][0][0],array()),$filename);
}
}
}

/**
*
*
* @param <string> $error -
*/

private function fatalerror($error){
trigger_error($error. "<br/>\n" , E_USER_ERROR);
die();
}
}


* This source code was highlighted with Source Code Highlighter .

Use on health.

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


All Articles