We usually create a PHP source file for each class when we write a Web application. In order to use these source files, we need to write a large number of include statements (Include,require) at the beginning of each script. In PHP 5, this is no longer necessary. We can implement our own loading source files by __autoload () functions and Spl_autoload_register functions, which are invoked automatically when attempting to use classes that have not yet been defined. By calling these functions, the script engine has the last chance to load the class required before the PHP error fails. The main goal of this article is to explain how to automate the loading of source files with C in the extension, but before we get acquainted with the method of implementing automatic loading in PHP scripts.
Implementing automatic Loading in scripts
In PHP 5 We can define a __autoload () function that is invoked automatically when trying to use a class that has not yet been defined, so that we can define some of our own loading rules.
<?php
function __autoload ($class _name) {
Require_once $class _name. '. php ';
}
$obj = new MyClass1 ();
$obj 2 = new MyClass2 ();
?>
With Spl_autoload_register we can register multiple load functions at once, and PHP will call in the registration order when attempting to use classes that have not yet been defined.
<?php
function autoload_services ($class _name)
{
$file = ' services/'. $class _name. '. php ';
if (file_exists ($file))
{
Require_once ($file);
}
}
function Autoload_vos ($class _name)
{
$file = ' vos/'. $class _name. '. php ';
if (file_exists ($file))
{
Require_once ($file);
}
}
Spl_autoload_register (' autoload_services ');
Spl_autoload_register (' Autoload_vos ');
?>
Implement automatic loading in PHP extensions
Recently in writing a PHP extension, one of the functions is to implement the automatic class loading, but also by calling the Spl_autoload_register function in the kernel. Using the Zend API to invoke the Spl_autoload_register function is relatively straightforward, let's talk about how to implement the functions of inclue/require/include_once/require_once and so on in the kernel. In fact, inclue/require/include_once/require_once and other instructions are mainly read into the file compiled and executed, the following method is completed these operations, the code has detailed comments.
/*
* Loader_import First compiles the PHP source file into Op_array, and then executes the opcode in sequence Op_array
*/
int Loader_import (char *path, int len tsrmls_dc) {
Zend_file_handle File_handle;
Zend_op_array *op_array;
Char Realpath[maxpathlen];
if (! Vcwd_realpath (path, Realpath)) {
return 0;
}
File_handle.filename = path;
File_handle.free_filename = 0;
File_handle.type = Zend_handle_filename;
File_handle.opened_path = NULL;
FILE_HANDLE.HANDLE.FP = NULL;
Invoke the Zend API to compile the source file
Op_array = Zend_compile_file (&file_handle, Zend_include tsrmls_cc);
if (Op_array && file_handle.handle.stream.handle) {
int dummy = 1;
if (!file_handle.opened_path) {
File_handle.opened_path = path;
}
//Registration of source files to global variables during execution (EG) in the Include_files list, which marks that the source file already contains the
zend_hash_add (&eg Included_files), File_handle.opened_path, strlen (File_handle.opened_path) +1, (void *) &dummy,
sizeof (int), NULL);
}
zend_destroy_file_handle (&file_handle tsrmls_cc);
Start Execution Op_array
if (Op_array) {
Zval *result = NULL;
Save the original execution environment, including ACTIVE_OP_ARRAY,OPLINE_PTR, etc.
Zval * * __old_return_value_pp = EG (return_value_ptr_ptr);
ZEND_OP * * __old_opline_ptr = EG (opline_ptr);
Zend_op_array * __old_op_array = EG (Active_op_array);
After the save environment completes, initialize the execution environment and replace the Op_array
EG (return_value_ptr_ptr) = &result;
EG (Active_op_array) = Op_array;
#if ((php_major_version = 5) && (Php_minor_version > 2)) | | (Php_major_version > 5)
if (! EG (active_symbol_table)) {
Zend_rebuild_symbol_table (Tsrmls_c);
}
#endif
Invoke the Zend API to execute the Op_array of the source file
Zend_execute (Op_array tsrmls_cc);
Op_array the execution is complete, destroy, or the memory will leak, haha
Destroy_op_array (Op_array tsrmls_cc);
Efree (Op_array);
Check whether the exception of the global variable (EG) during execution is marked to determine if there is an exception
if (! EG (Exception)) {
if (EG (return_value_ptr_ptr) && *eg (return_value_ptr_ptr)) {
Zval_ptr_dtor (EG (return_value_ptr_ptr));
}
}
OK, execute here to explain the source file Op_array has been completed, we have to restore the original execution environment
EG (return_value_ptr_ptr) = __old_return_value_pp;
EG (opline_ptr) = __old_opline_ptr;
EG (Active_op_array) = __old_op_array;
return 1;
}
return 0;
}