📜 ⬆️ ⬇️

Increase Zend Framework's performance by collecting its classes in one file.

Every time you launch a link, and ZendFramwork processes it on the server, there are unpleasant performance costs when building the PHP executable code with the interpreter.

PHP can of course cache the opcode in memory using APC, Memcached, etc. But before taking the opcode from memory, the hard disk is being accessed to make sure that the last modified date was updated. When files are small, this happens unnoticed. When there are many of them, a decrease in productivity begins to become noticeable.

(In APC, of ​​course, you can configure that PHP interpreter does not check the date of files, but any change in files requires Apache to be restarted, which is not very convenient when developing).
')
The network has already met class assemblers, but they are not always correctly collected what you need.

Yes, this topic has already been raised several times, but I never found a single script that would correctly connect the classes Zend_Controller_Router_Route_Abstract and Zend_Controller_Router_Route_Chain.



Just run through the files and collect them into one does not work. In the circle, inheritance from classes and interfaces is used. And for correct compiling it is necessary that the class that goes after implements or extends be declared in the code earlier.

This feature is implemented in the next class and when building, I do not think that you have any problems.

So, you can run the compiler at the very end of the script execution after Zend_Controller_Front :: getInstance () -> dispatch (); (usually this line in index.php in the root folder of your project) using the following code:
ZCompile::make( 'd:/www/project/lib/zendframework-1.7.1/Zend.compiled.phplib' ,
array(),
'd:/www/project/lib/zendframework-1.7.1/'
);


* This source code was highlighted with Source Code Highlighter .


The first parameter specifies the path to the file into which all classes will be collected.
The second parameter contains an array of additional files that need to be connected (about it a bit later).
The third parameter contains the path to the framework library, at the end a forward slash is required '/'! This directory is called Zend. Those. in my example, the Zend class files are in the d directory: /www/project/lib/zendframework-1.7.1/Zend/. Again, you only need to specify the path to the Zend folder.

After running the script, ZCompile will automatically take a list of necessary classes and write them into one file, observing the inheritance hierarchy.

In the code, I usually use the following construction to choose to load the framework from the assembled file or from the standard library:
if (FRAMEWORK_LOAD_COMPILED_ZEND==1) {
require 'Zend.compiled.phplib' ;
} else {
require 'Zend/Loader.php' ;
}
Zend_Loader::registerAutoload( 'Zend_Loader' );


* This source code was highlighted with Source Code Highlighter .

It is very convenient to keep the “compiled” file and the ZCompile class on the same level as the Zend folder (the framework library). Those. I have them stored in the directory d: /www/project/lib/zendframework-1.7.1/

So, remember, I told you about the second parameter , which is an array. So, it allows you to connect those classes that were not used in the current script, but are needed in the project.
There simply indicate the main classes or directories that you want to connect. For example:
array(
'Zend/Auth/' , // ,
'Zend/Acl/' , // ,
'Zend/View/Helper/HeadTitle.php' , //
'Zend/View/Helper/Url.php' , //
)


* This source code was highlighted with Source Code Highlighter .


When a directory is connected, all files are read only at the current level, we don’t go into the subdirectories. When we connect a pure class, we read only it.
BUT when connecting a class (through a directory or directly) ZCompile collects all the classes necessary for the specified file to work. Those. if you specify the 'Zend / Auth /' directory, then it will most likely collect everything contained in the specified folder including subdirectories.

You can simply execute the following code in a separate file, which will simply collect Acl and Auth for you:
<?php

set_include_path(
'd:/www/ksystem/lib/zendframework-1.7.1/'
. PATH_SEPARATOR . get_include_path());

ZCompile::make( 'd:/www/project/lib/zendframework-1.7.1/Zend.compiled.phplib' ,
array( 'Zend/Auth/' , 'Zend/Acl/' ),
'd:/www/ksystem/lib/zendframework-1.7.1/'
);
?>


* This source code was highlighted with Source Code Highlighter .


So, the ZCompile class itself (we don’t find fault with mistakes in the comments, this is not the main thing! There was no time to fix them;)):
<?php
/**
* ZendFramwork .
*
* @author Nod nodkz.at.mail.ru
*/
class ZCompile
{
static private $path;

/**
* , require/include,
*
* @param string $dest
* @param string $includes ZF
* @return array
*/
public static function make($dest, array $add_includes = array(), $path = '' )
{
self::$path=$path;
$includes=array_merge($add_includes, self::_scanFolderFiles($add_includes), self::_getZendIncludes());

//
foreach ($includes as $key=>&$ value ) {
if (substr($ value ,0,1)== '/' ) {
$includes[$key] = substr($ value ,1);
}
}

//
$ordered_include=Array();
foreach ($includes as $class_file) {
self::_getClassOrderIncludes($class_file, $ordered_include);
}

// '<?php' '? >', , require/include[_once]
//
$pattern[] = '%(^\<\?php|\?\>$)%m' ;
$replacement[] = '' ;
$pattern[] = '%/\*.*?\*/%sm' ;
$replacement[] = '' ;
//$pattern[] ='%//.*$%m';
//$replacement[] = '';
$pattern[] = '%(require_once|include_once|require|include) [("\'](.*?)[)"\'];%sm' ;
$replacement[] = '' ;
$pattern[] = '%(\n){2,}%' ;
$replacement[] = "\n" ;

$body = "<?php\n" ;
$worked_classes = Array();
foreach ($ordered_include as &$fname) {
if (!in_array($fname, $worked_classes)) {
$worked_classes[] = $fname;

$fname = self::$path.$fname;
if (@file_exists($fname)&&is_file($fname)) {
$body.= "/*** FILE: " .$fname. " ***/ \r\n" ;
$body .= preg_replace($pattern, $replacement, file_get_contents($fname, true ));
}
}
}

$size = file_put_contents($dest, $body);

return array( 'includes' => $includes, 'compiledBody' => $body, 'compiledSize' => $size);
}

/**
* (.. /).
* php , ( ).
*
* @param array $add_includes
* @return array
*/
private static function _scanFolderFiles(&$add_includes) {
$add_includes_dirs=array();
foreach ($add_includes as $key=>$elem) {
if (substr($elem,-1)== '/' ) {
if (is_dir(self::$path.$elem)) {
if ($dh = opendir(self::$path.$elem)) {
while (($file = readdir($dh)) !== false ) {
if (strpos(strtolower($file), '.php' )!== false ) {
$add_includes_dirs[]=$elem.$file;
}
}
closedir($dh);
}
}
$add_includes[$key]= '' ;
}
}
return $add_includes_dirs;
}

/**
* , .
*
* @param string $fname
* @param array &$already_included
*/
private static function _getClassOrderIncludes($class_filename, array &$already_included=Array(), array &$stack=Array()) {
//
if (!in_array($class_filename, $stack)) {
array_push($stack, $class_filename);
} else {
if (!in_array($class_filename, $already_included)) {
$already_included[]=$class_filename;
}
return ;
}

//
if (is_file(self::$path.$class_filename) && !in_array($class_filename, $already_included)) {
$class_file_content = file_get_contents(self::$path.$class_filename, true );

//
// .. extends implements,
//
if (preg_match_all( '/class\s+[_\w]+\s+(extends|implements)\s+([_\w]+)/i' , $class_file_content, $arr)) {
foreach ($arr[2] as $new_class_name) {
$new_class_path = str_replace( '_' , '/' ,$new_class_name). '.php' ;
if (!in_array($new_class_path, $already_included)) {
self::_getClassOrderIncludes($new_class_path, $already_included, $stack);
}
}
}

//
if (preg_match_all( '%(require_once|include_once|require|include) [("\'](.*?)[)"\'];%sm' , $class_file_content, $arr)) {
//
foreach ($arr[2] as $new_class_path) {
// , ,
if (!in_array($new_class_path, $already_included) && !in_array($new_class_path, $stack)) {
//
if (strpos($new_class_path, '$' )=== false ) {
// ,
self::_getClassOrderIncludes($new_class_path, $already_included, $stack);
}
}
}
}
if (!in_array($class_filename, $already_included)) {
$already_included[]=$class_filename;
}
}

array_pop($stack);
}

/**
* ZF
*
* @return array
*/
private static function _getZendIncludes()
{
$required = array();
$included_files = get_included_files();
$included_files;
foreach ($included_files as $fname) {
$fname = str_replace( '/' , '\\',$fname);

if (!(strpos($fname, '
\\Zend\\ ') > 0) || (strstr($fname, __CLASS__ . ' .php '))) {
continue;
}

$required[] = str_replace('
\\ ', ' / ', substr($fname, strpos($fname, ' \\Zend\\'), strlen($fname)));
}

return array_unique($required);
}
}
?>


* This source code was highlighted with Source Code Highlighter .


Download class

Use, on health.

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


All Articles