diff --git a/README.md b/README.md index 6e00b84..56a71b1 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ cd ext-rayaop ``` phpize ./configure -make +make --enable-rayaop-quiet // Suppress E_NOTICE to indicate experimental. make install ``` diff --git a/config.m4 b/config.m4 index 03bfadf..4244685 100644 --- a/config.m4 +++ b/config.m4 @@ -34,4 +34,11 @@ if test "$PHP_RAYAOP" != "no"; then dnl Add instruction to install header files dnl link https://www.phpinternalsbook.com/build_system/build_system.html#php-install-headers PHP_INSTALL_HEADERS([ext/rayaop], [php_rayaop.h]) + + PHP_ARG_ENABLE(rayaop-quiet, whether to suppress experimental notices, + [ --enable-rayaop-quiet Suppress experimental notices], no, yes) + + if test "$PHP_RAYAOP_QUIET" != "no"; then + AC_DEFINE(RAYAOP_QUIET, 1, [Whether to suppress experimental notices]) + fi fi diff --git a/php_rayaop.h b/php_rayaop.h index cd8e9c3..8be48d3 100644 --- a/php_rayaop.h +++ b/php_rayaop.h @@ -1,91 +1,99 @@ -#ifndef PHP_RAYAOP_H // If PHP_RAYAOP_H is not defined -#define PHP_RAYAOP_H // Define PHP_RAYAOP_H (header guard) +/* If PHP_RAYAOP_H is not defined, then define PHP_RAYAOP_H (header guard) */ +#ifndef PHP_RAYAOP_H +#define PHP_RAYAOP_H -#ifdef HAVE_CONFIG_H // If HAVE_CONFIG_H is defined -#include "config.h" // Include config.h +/* If HAVE_CONFIG_H is defined, then include config.h */ +#ifdef HAVE_CONFIG_H +#include "config.h" #endif -#include "php.h" // Include PHP core header file -#include "php_ini.h" // Include PHP INI related header file -#include "ext/standard/info.h" // Include standard extension module information related header -#include "zend_exceptions.h" // Include Zend exception handling related header -#include "zend_interfaces.h" // Include Zend interface related header +#include "php.h" /* Include PHP core header file */ +#include "php_ini.h" /* Include PHP INI related header file */ +#include "ext/standard/info.h" /* Include standard extension module information related header */ +#include "zend_exceptions.h" /* Include Zend exception handling related header */ +#include "zend_interfaces.h" /* Include Zend interface related header */ -#ifdef ZTS // If in thread-safe mode -#include "TSRM.h" // Include Thread Safe Resource Manager +/* If in thread-safe mode, then include Thread Safe Resource Manager */ +#ifdef ZTS +#include "TSRM.h" #endif -#define PHP_RAYAOP_VERSION "1.0.0" // Define RayAOP extension version -#define RAYAOP_NS "Ray\\Aop\\" // Define RayAOP namespace +/* Define RayAOP namespace */ +#define RAYAOP_NS "Ray\\Aop\\" -extern zend_module_entry rayaop_module_entry; // Declare rayaop module entry as external reference -#define phpext_rayaop_ptr &rayaop_module_entry // Define pointer to rayaop module +/* Declare rayaop module entry as external reference */ +extern zend_module_entry rayaop_module_entry; -#ifdef PHP_WIN32 // If in Windows environment -#define PHP_RAYAOP_API __declspec(dllexport) // Specify DLL export -#elif defined(__GNUC__) && __GNUC__ >= 4 // If using GCC 4 or later -#define PHP_RAYAOP_API __attribute__ ((visibility("default"))) // Specify default visibility -#else // For other environments -#define PHP_RAYAOP_API // No specific definition -#endif +/* Define pointer to rayaop module */ +#define phpext_rayaop_ptr &rayaop_module_entry -#ifdef ZTS // If in thread-safe mode -#include "TSRM.h" // Include Thread Safe Resource Manager again (redundant but for safety) +/* If in Windows environment, specify DLL export */ +#ifdef PHP_WIN32 +#define PHP_RAYAOP_API __declspec(dllexport) +/* If using GCC 4 or later, specify default visibility */ +#elif defined(__GNUC__) && __GNUC__ >= 4 +#define PHP_RAYAOP_API __attribute__ ((visibility("default"))) +/* For other environments, no specific definition is made */ +#else +#define PHP_RAYAOP_API #endif -// Macro for debug output -#ifdef RAYAOP_DEBUG // If debug mode is enabled -#define RAYAOP_DEBUG_PRINT(fmt, ...) php_printf("RAYAOP DEBUG: " fmt "\n", ##__VA_ARGS__) // Define debug output macro -#else // If debug mode is disabled -#define RAYAOP_DEBUG_PRINT(fmt, ...) // Do nothing +/* If in thread-safe mode, include Thread Safe Resource Manager again (redundant but for safety) */ +#ifdef ZTS +#include "TSRM.h" #endif -// Error codes -#define RAYAOP_ERROR_MEMORY_ALLOCATION 1 // Error code for memory allocation -#define RAYAOP_ERROR_HASH_UPDATE 2 // Error code for hash update - -/** - * Structure to hold intercept information - * link: http://www.phpinternalsbook.com/php5/classes_objects/internal_structures_and_implementation.html - * link: http://php.adamharvey.name/manual/ja/internals2.variables.tables.php - */ -typedef struct _intercept_info { - zend_string *class_name; // Class name to intercept - zend_string *method_name; // Method name to intercept - zval handler; // Intercept handler -} intercept_info; - -// Function declarations -PHP_MINIT_FUNCTION(rayaop); // Module initialization function -PHP_MSHUTDOWN_FUNCTION(rayaop); // Module shutdown function -PHP_RINIT_FUNCTION(rayaop); // Request initialization function -PHP_RSHUTDOWN_FUNCTION(rayaop); // Request shutdown function -PHP_MINFO_FUNCTION(rayaop); // Module information function - -PHP_FUNCTION(method_intercept); // Method intercept function - -// Utility function declarations -void rayaop_handle_error(const char *message); // Error handling function -bool rayaop_should_intercept(zend_execute_data *execute_data); // Function to determine if interception is necessary -char* rayaop_generate_intercept_key(zend_string *class_name, zend_string *method_name, size_t *key_len); // Function to generate intercept key -intercept_info* rayaop_find_intercept_info(const char *key, size_t key_len); // Function to search for intercept information -void rayaop_execute_intercept(zend_execute_data *execute_data, intercept_info *info); // Function to execute interception -void rayaop_free_intercept_info(zval *zv); // Function to free intercept information - -#ifdef RAYAOP_DEBUG // If debug mode is enabled -void rayaop_debug_print_zval(zval *value); // Function to debug print zval value -void rayaop_dump_intercept_info(void); // Function to dump intercept information +/* Macro for debug output */ +#ifdef RAYAOP_DEBUG /* If debug mode is enabled */ +#define PHP_RAYAOP_DEBUG_PRINT(fmt, ...) php_printf("RAYAOP DEBUG: " fmt "\n", ##__VA_ARGS__) /* Define debug output macro */ +#else /* If debug mode is disabled */ +#define PHP_RAYAOP_DEBUG_PRINT(fmt, ...) /* Do nothing */ #endif -ZEND_BEGIN_MODULE_GLOBALS(rayaop) // Start of rayaop module global variables - HashTable *intercept_ht; // Intercept hash table - zend_bool is_intercepting; // Intercepting flag -ZEND_END_MODULE_GLOBALS(rayaop) // End of rayaop module global variables +/* Error codes */ +#define RAYAOP_ERROR_MEMORY_ALLOCATION 1 /* Error code for memory allocation */ +#define RAYAOP_ERROR_HASH_UPDATE 2 /* Error code for hash update */ + +/* Structure to hold intercept information */ +typedef struct _php_rayaop_intercept_info { + zend_string *class_name; /* Class name to intercept */ + zend_string *method_name; /* Method name to intercept */ + zval handler; /* Intercept handler */ +} php_rayaop_intercept_info; + +/* Function declarations */ +PHP_MINIT_FUNCTION(rayaop); /* Module initialization function */ +PHP_MSHUTDOWN_FUNCTION(rayaop); /* Module shutdown function */ +PHP_RINIT_FUNCTION(rayaop); /* Request initialization function */ +PHP_RSHUTDOWN_FUNCTION(rayaop); /* Request shutdown function */ +PHP_MINFO_FUNCTION(rayaop); /* Module information function */ +PHP_FUNCTION(method_intercept); /* Method intercept function */ + +/* Utility function declarations */ +void php_rayaop_handle_error(const char *message); /* Error handling function */ +bool php_rayaop_should_intercept(zend_execute_data *execute_data); /* Function to determine if interception is necessary */ +char *php_rayaop_generate_intercept_key(zend_string *class_name, zend_string *method_name, size_t *key_len); /* Function to generate intercept key */ +php_rayaop_intercept_info *php_rayaop_find_intercept_info(const char *key, size_t key_len); /* Function to search for intercept information */ +void php_rayaop_execute_intercept(zend_execute_data *execute_data, php_rayaop_intercept_info *info); /* Function to execute interception */ +void php_rayaop_free_intercept_info(zval *zv); /* Function to free intercept information */ + +#ifdef RAYAOP_DEBUG /* If debug mode is enabled */ +void php_rayaop_debug_print_zval(zval *value); /* Function to debug print zval value */ +void php_rayaop_dump_intercept_info(void); /* Function to dump intercept information */ +#endif -#ifdef ZTS // If in thread-safe mode -#define RAYAOP_G(v) TSRMG(rayaop_globals_id, zend_rayaop_globals *, v) // Global variable access macro (thread-safe version) -#else // If in non-thread-safe mode -#define RAYAOP_G(v) (rayaop_globals.v) // Global variable access macro (non-thread-safe version) +ZEND_BEGIN_MODULE_GLOBALS(rayaop) + /* Start of rayaop module global variables */ + HashTable *intercept_ht; /* Intercept hash table */ + zend_bool is_intercepting; /* Intercepting flag */ +ZEND_END_MODULE_GLOBALS(rayaop) /* End of rayaop module global variables */ + +/* If in thread-safe mode, global variable access macro (thread-safe version) */ +#ifdef ZTS +#define RAYAOP_G(v) TSRMG(rayaop_globals_id, zend_rayaop_globals *, v) +/* If in non-thread-safe mode, global variable access macro (non-thread-safe version) */ +#else +#define RAYAOP_G(v) (rayaop_globals.v) #endif -#endif /* PHP_RAYAOP_H */ // End of header guard \ No newline at end of file +#endif /* End of header guard */ \ No newline at end of file diff --git a/rayaop.c b/rayaop.c index c20b02f..1652093 100644 --- a/rayaop.c +++ b/rayaop.c @@ -1,400 +1,476 @@ #ifdef HAVE_CONFIG_H -#include "config.h" // Include configuration file +#include "config.h" /* Include configuration file */ #endif -#include "php_rayaop.h" // Include header file for RayAOP extension +#define PHP_RAYAOP_VERSION "0.1.0" -// Declaration of module global variables +#ifndef RAYAOP_QUIET +#define RAYAOP_QUIET 0 +#endif + +#include "php_rayaop.h" /* Include header file for RayAOP extension */ + +/* Declaration of module global variables */ ZEND_DECLARE_MODULE_GLOBALS(rayaop) -// Declaration of static variable: pointer to the original zend_execute_ex function -static void (*original_zend_execute_ex)(zend_execute_data *execute_data); +/* Declaration of static variable: pointer to the original zend_execute_ex function */ +static void (*php_rayaop_original_execute_ex)(zend_execute_data *execute_data); -/** - * Global initialization function - * - * @param zend_rayaop_globals *rayaop_globals Pointer to global variables - */ -static void php_rayaop_init_globals(zend_rayaop_globals *rayaop_globals) -{ - rayaop_globals->intercept_ht = NULL; // Initialize intercept hash table - rayaop_globals->is_intercepting = 0; // Initialize intercept flag +/* {{{ proto void php_rayaop_init_globals(zend_rayaop_globals *rayaop_globals) + Global initialization function + + This function initializes the global variables for the RayAOP extension. + + @param zend_rayaop_globals *rayaop_globals Pointer to global variables +*/ +static void php_rayaop_init_globals(zend_rayaop_globals *rayaop_globals) { + rayaop_globals->intercept_ht = NULL; /* Initialize intercept hash table */ + rayaop_globals->is_intercepting = 0; /* Initialize intercept flag */ } +/* }}} */ -// Macro for debug output +/* Macro for debug output */ #ifdef RAYAOP_DEBUG -#define RAYAOP_DEBUG_PRINT(fmt, ...) php_printf("RAYAOP DEBUG: " fmt "\n", ##__VA_ARGS__) // Output debug information +#define PHP_RAYAOP_DEBUG_PRINT(fmt, ...) php_printf("RAYAOP DEBUG: " fmt "\n", ##__VA_ARGS__) /* Output debug information */ #else -#define RAYAOP_DEBUG_PRINT(fmt, ...) // Do nothing if not in debug mode +#define PHP_RAYAOP_DEBUG_PRINT(fmt, ...) /* Do nothing if not in debug mode */ #endif -// Argument information for method_intercept function +/* Argument information for method_intercept function */ ZEND_BEGIN_ARG_INFO_EX(arginfo_method_intercept, 0, 0, 3) - ZEND_ARG_TYPE_INFO(0, class_name, IS_STRING, 0) // Argument information for class name - ZEND_ARG_TYPE_INFO(0, method_name, IS_STRING, 0) // Argument information for method name - ZEND_ARG_OBJ_INFO(0, interceptor, Ray\\Aop\\MethodInterceptorInterface, 0) // Argument information for intercept handler + ZEND_ARG_TYPE_INFO(0, class_name, IS_STRING, 0) /* Argument information for class name */ + ZEND_ARG_TYPE_INFO(0, method_name, IS_STRING, 0) /* Argument information for method name */ + ZEND_ARG_OBJ_INFO(0, interceptor, Ray\\Aop\\MethodInterceptorInterface, 0) /* Argument information for intercept handler */ ZEND_END_ARG_INFO() -// Implementation of utility functions +/* {{{ proto void php_rayaop_handle_error(const char *message) + Error handling function -/** - * Error handling function - * - * @param const char *message Error message - */ -void rayaop_handle_error(const char *message) { - php_error_docref(NULL, E_ERROR, "Memory error: %s", message); // Output error message + This function handles errors by outputting an error message. + + @param const char *message Error message to be displayed +*/ +void php_rayaop_handle_error(const char *message) { + php_error_docref(NULL, E_ERROR, "Memory error: %s", message); /* Output error message */ } +/* }}} */ + +/* {{{ proto bool php_rayaop_should_intercept(zend_execute_data *execute_data) + Function to determine if interception is necessary -/** - * Function to determine if interception is necessary - * - * @param zend_execute_data *execute_data Execution data - * @return bool true if interception is necessary - */ -bool rayaop_should_intercept(zend_execute_data *execute_data) { - return execute_data->func->common.scope && // Scope exists - execute_data->func->common.function_name && // Function name exists - !RAYAOP_G(is_intercepting); // Not currently intercepting + This function checks if the current execution should be intercepted. + + @param zend_execute_data *execute_data Execution data + @return bool Returns true if interception is necessary, false otherwise +*/ +bool php_rayaop_should_intercept(zend_execute_data *execute_data) { + return execute_data->func->common.scope && /* Scope exists */ + execute_data->func->common.function_name && /* Function name exists */ + !RAYAOP_G(is_intercepting); /* Not currently intercepting */ } +/* }}} */ + +/* {{{ proto char* php_rayaop_generate_intercept_key(zend_string *class_name, zend_string *method_name, size_t *key_len) + Function to generate intercept key -/** - * Function to generate intercept key - * - * @param zend_string *class_name Class name - * @param zend_string *method_name Method name - * @param size_t *key_len Pointer to store the key length - * @return char* Generated key - */ -char* rayaop_generate_intercept_key(zend_string *class_name, zend_string *method_name, size_t *key_len) { + This function creates a key in the format "class_name::method_name" for use in the intercept hash table. + + @param zend_string *class_name The name of the class + @param zend_string *method_name The name of the method + @param size_t *key_len Pointer to store the length of the generated key + @return char* The generated key, which must be freed by the caller using efree() +*/ +char *php_rayaop_generate_intercept_key(zend_string *class_name, zend_string *method_name, size_t *key_len) { char *key = NULL; - *key_len = spprintf(&key, 0, "%s::%s", ZSTR_VAL(class_name), ZSTR_VAL(method_name)); // Generate key in the format class_name::method_name - RAYAOP_DEBUG_PRINT("Generated key: %s", key); // Output generated key for debugging + *key_len = spprintf(&key, 0, "%s::%s", ZSTR_VAL(class_name), ZSTR_VAL(method_name)); + /* Generate key in the format class_name::method_name */ + PHP_RAYAOP_DEBUG_PRINT("Generated key: %s", key); /* Output generated key for debugging */ return key; } +/* }}} */ -/** - * Function to search for intercept information - * - * @param const char *key Search key - * @param size_t key_len Key length - * @return intercept_info* Found intercept information, NULL if not found - */ -intercept_info* rayaop_find_intercept_info(const char *key, size_t key_len) { - return zend_hash_str_find_ptr(RAYAOP_G(intercept_ht), key, key_len); // Search for intercept information in hash table -} +/* {{{ proto php_rayaop_intercept_info* php_rayaop_find_intercept_info(const char *key, size_t key_len) + Function to search for intercept information -/** - * Function to execute interception - * - * @param zend_execute_data *execute_data Execution data - * @param intercept_info *info Intercept information - */ -void rayaop_execute_intercept(zend_execute_data *execute_data, intercept_info *info) { - if (Z_TYPE(info->handler) != IS_OBJECT) { // If handler is not an object - return; // Abort processing - } + This function searches for intercept information in the hash table using the provided key. - if (execute_data->This.value.obj == NULL) { // If target object is NULL - RAYAOP_DEBUG_PRINT("Object is NULL, calling original function"); // Output debug information - original_zend_execute_ex(execute_data); // Execute original function - return; // Abort processing - } + @param const char *key The key to search for + @param size_t key_len The length of the key + @return php_rayaop_intercept_info* Pointer to the intercept information if found, NULL otherwise +*/ +php_rayaop_intercept_info *php_rayaop_find_intercept_info(const char *key, size_t key_len) { + return zend_hash_str_find_ptr(RAYAOP_G(intercept_ht), key, key_len); + /* Search for intercept information in hash table */ +} +/* }}} */ - zval retval, params[3]; // Prepare variables to store return value and arguments - ZVAL_OBJ(¶ms[0], execute_data->This.value.obj); // 1st argument: target object - ZVAL_STR(¶ms[1], info->method_name); // 2nd argument: method name +/* {{{ Helper function to prepare intercept parameters */ +static void prepare_intercept_params(zend_execute_data *execute_data, zval *params, php_rayaop_intercept_info *info) { + ZVAL_OBJ(¶ms[0], execute_data->This.value.obj); + ZVAL_STR(¶ms[1], info->method_name); - array_init(¶ms[2]); // Initialize array to store method arguments as 3rd argument - uint32_t arg_count = ZEND_CALL_NUM_ARGS(execute_data); // Get number of arguments - zval *args = ZEND_CALL_ARG(execute_data, 1); // Get argument array - for (uint32_t i = 0; i < arg_count; i++) { // For each argument + array_init(¶ms[2]); + uint32_t arg_count = ZEND_CALL_NUM_ARGS(execute_data); + zval *args = ZEND_CALL_ARG(execute_data, 1); + for (uint32_t i = 0; i < arg_count; i++) { zval *arg = &args[i]; - Z_TRY_ADDREF_P(arg); // Increase reference count - add_next_index_zval(¶ms[2], arg); // Add to array + Z_TRY_ADDREF_P(arg); + add_next_index_zval(¶ms[2], arg); } +} +/* }}} */ - RAYAOP_G(is_intercepting) = 1; // Set intercept flag +/* {{{ Helper function to call the intercept handler */ +static bool call_intercept_handler(zval *handler, zval *params, zval *retval) { zval func_name; - ZVAL_STRING(&func_name, "intercept"); // Set function name to call + ZVAL_STRING(&func_name, "intercept"); + + bool success = (call_user_function(NULL, handler, &func_name, retval, 3, params) == SUCCESS); + + zval_ptr_dtor(&func_name); + return success; +} +/* }}} */ + +/* {{{ Helper function to clean up after interception */ +static void cleanup_intercept(zval *params, zval *retval) { + zval_ptr_dtor(¶ms[1]); + zval_ptr_dtor(¶ms[2]); + zval_ptr_dtor(retval); +} +/* }}} */ + +/* {{{ proto void php_rayaop_execute_intercept(zend_execute_data *execute_data, php_rayaop_intercept_info *info) + Main function to execute method interception */ +void php_rayaop_execute_intercept(zend_execute_data *execute_data, php_rayaop_intercept_info *info) { + PHP_RAYAOP_DEBUG_PRINT("Executing intercept for %s::%s", ZSTR_VAL(info->class_name), ZSTR_VAL(info->method_name)); - ZVAL_UNDEF(&retval); // Initialize return value as undefined - if (call_user_function(NULL, &info->handler, &func_name, &retval, 3, params) == SUCCESS) { // Call intercept function - if (!Z_ISUNDEF(retval)) { // If return value is defined - ZVAL_COPY(execute_data->return_value, &retval); // Copy return value + if (Z_TYPE(info->handler) != IS_OBJECT) { + PHP_RAYAOP_DEBUG_PRINT("Invalid handler, skipping interception"); + return; + } + + if (execute_data->This.value.obj == NULL) { + PHP_RAYAOP_DEBUG_PRINT("Object is NULL, calling original function"); + php_rayaop_original_execute_ex(execute_data); + return; + } + + zval retval, params[3]; + prepare_intercept_params(execute_data, params, info); + + RAYAOP_G(is_intercepting) = 1; + + ZVAL_UNDEF(&retval); + if (call_intercept_handler(&info->handler, params, &retval)) { + if (!Z_ISUNDEF(retval)) { + ZVAL_COPY(execute_data->return_value, &retval); } - } else { // If interception fails - php_error_docref(NULL, E_WARNING, "Interception failed for %s::%s", ZSTR_VAL(info->class_name), ZSTR_VAL(info->method_name)); // Output warning + } else { + php_error_docref(NULL, E_WARNING, "Interception failed for %s::%s", ZSTR_VAL(info->class_name), ZSTR_VAL(info->method_name)); } - zval_ptr_dtor(&retval); // Free memory for return value - zval_ptr_dtor(&func_name); // Free memory for function name - zval_ptr_dtor(¶ms[1]); // Free memory for method name - zval_ptr_dtor(¶ms[2]); // Free memory for argument array + cleanup_intercept(params, &retval); + RAYAOP_G(is_intercepting) = 0; - RAYAOP_G(is_intercepting) = 0; // Reset intercept flag + PHP_RAYAOP_DEBUG_PRINT("Interception completed for %s::%s", ZSTR_VAL(info->class_name), ZSTR_VAL(info->method_name)); } - -/** - * Function to free intercept information - * - * @param zval *zv zval containing intercept information to be freed - */ -void rayaop_free_intercept_info(zval *zv) { - intercept_info *info = Z_PTR_P(zv); // Get intercept information pointer from zval - if (info) { // If intercept information exists - RAYAOP_DEBUG_PRINT("Freeing intercept info for %s::%s", ZSTR_VAL(info->class_name), ZSTR_VAL(info->method_name)); // Output debug information - zend_string_release(info->class_name); // Free memory for class name - zend_string_release(info->method_name); // Free memory for method name - zval_ptr_dtor(&info->handler); // Free memory for handler - efree(info); // Free memory for intercept information structure +/* }}} */ + +/* {{{ proto void php_rayaop_free_intercept_info(zval *zv) + Function to free intercept information + + This function frees the memory allocated for intercept information. + + @param zval *zv The zval containing the intercept information to be freed +*/ +void php_rayaop_free_intercept_info(zval *zv) { + php_rayaop_intercept_info *info = Z_PTR_P(zv); /* Get intercept information pointer from zval */ + if (info) { + /* If intercept information exists */ + PHP_RAYAOP_DEBUG_PRINT("Freeing intercept info for %s::%s", ZSTR_VAL(info->class_name), ZSTR_VAL(info->method_name)); + /* Output debug information */ + zend_string_release(info->class_name); /* Free memory for class name */ + zend_string_release(info->method_name); /* Free memory for method name */ + zval_ptr_dtor(&info->handler); /* Free memory for handler */ + efree(info); /* Free memory for intercept information structure */ } } +/* }}} */ -/** - * Custom zend_execute_ex function - * - * @param zend_execute_data *execute_data Execution data - */ -static void rayaop_zend_execute_ex(zend_execute_data *execute_data) { - RAYAOP_DEBUG_PRINT("rayaop_zend_execute_ex called"); // Output debug information - - if (!rayaop_should_intercept(execute_data)) { // If interception is not necessary - original_zend_execute_ex(execute_data); // Call the original execution function - return; // End processing - } +/* {{{ proto void php_rayaop_execute_ex(zend_execute_data *execute_data) + Custom zend_execute_ex function - zend_function *current_function = execute_data->func; // Get current function information - zend_string *class_name = current_function->common.scope->name; // Get class name - zend_string *method_name = current_function->common.function_name; // Get method name + This function replaces the original zend_execute_ex function to implement method interception. - size_t key_len; - char *key = rayaop_generate_intercept_key(class_name, method_name, &key_len); // Generate intercept key + @param zend_execute_data *execute_data The execution data +*/ +static void php_rayaop_execute_ex(zend_execute_data *execute_data) { + PHP_RAYAOP_DEBUG_PRINT("php_rayaop_execute_ex called"); /* Output debug information */ + + if (!php_rayaop_should_intercept(execute_data)) { + /* If interception is not necessary */ + php_rayaop_original_execute_ex(execute_data); /* Call the original execution function */ + return; /* End processing */ + } - intercept_info *info = rayaop_find_intercept_info(key, key_len); // Search for intercept information + zend_function *current_function = execute_data->func; /* Get current function information */ + zend_string *class_name = current_function->common.scope->name; /* Get class name */ + zend_string *method_name = current_function->common.function_name; /* Get method name */ - if (info) { // If intercept information is found - RAYAOP_DEBUG_PRINT("Found intercept info for key: %s", key); // Output debug information - rayaop_execute_intercept(execute_data, info); // Execute interception - } else { // If intercept information is not found - RAYAOP_DEBUG_PRINT("No intercept info found for key: %s", key); // Output debug information - original_zend_execute_ex(execute_data); // Call the original execution function + size_t key_len; + char *key = php_rayaop_generate_intercept_key(class_name, method_name, &key_len); /* Generate intercept key */ + + php_rayaop_intercept_info *info = php_rayaop_find_intercept_info(key, key_len); /* Search for intercept information */ + + if (info) { + /* If intercept information is found */ + PHP_RAYAOP_DEBUG_PRINT("Found intercept info for key: %s", key); /* Output debug information */ + php_rayaop_execute_intercept(execute_data, info); /* Execute interception */ + } else { + /* If intercept information is not found */ + PHP_RAYAOP_DEBUG_PRINT("No intercept info found for key: %s", key); /* Output debug information */ + php_rayaop_original_execute_ex(execute_data); /* Call the original execution function */ } - efree(key); // Free memory for key + efree(key); /* Free memory for key */ } - -/** - * Handling for hash table update failure - * - * @param intercept_info *new_info New intercept information - * @param char *key Key used for update - */ -void hash_update_failed(intercept_info *new_info, char *key) { - rayaop_handle_error("Failed to update intercept hash table"); // Output error message - zend_string_release(new_info->class_name); // Free memory for class name - zend_string_release(new_info->method_name); // Free memory for method name - zval_ptr_dtor(&new_info->handler); // Free memory for handler - efree(new_info); // Free memory for intercept information structure - efree(key); // Free memory for key +/* }}} */ + +/* {{{ proto void php_rayaop_hash_update_failed(php_rayaop_intercept_info *new_info, char *key) + Handling for hash table update failure + + This function handles the case when updating the intercept hash table fails. + + @param php_rayaop_intercept_info *new_info The new intercept information that failed to be added + @param char *key The key that was used for the failed update +*/ +void php_rayaop_hash_update_failed(php_rayaop_intercept_info *new_info, char *key) { + php_rayaop_handle_error("Failed to update intercept hash table"); /* Output error message */ + zend_string_release(new_info->class_name); /* Free memory for class name */ + zend_string_release(new_info->method_name); /* Free memory for method name */ + zval_ptr_dtor(&new_info->handler); /* Free memory for handler */ + efree(new_info); /* Free memory for intercept information structure */ + efree(key); /* Free memory for key */ } +/* }}} */ + +/* {{{ proto bool method_intercept(string class_name, string method_name, object intercepted) + Function to register intercept method -/** - * Function to register intercept method - * link: https://www.phpinternalsbook.com/php7/extensions_design/php_functions.html - * - * @param INTERNAL_FUNCTION_PARAMETERS Internal function parameters - */ + This function registers an interceptor for a specified class method. + + @param string class_name The name of the class + @param string method_name The name of the method + @param object intercepted The interceptor object + @return bool Returns TRUE on success or FALSE on failure +*/ PHP_FUNCTION(method_intercept) { - RAYAOP_DEBUG_PRINT("method_intercept called"); // Output debug information + PHP_RAYAOP_DEBUG_PRINT("method_intercept called"); /* Output debug information */ - char *class_name, *method_name; // Pointers for class name and method name - size_t class_name_len, method_name_len; // Lengths of class name and method name - zval *intercepted; // Intercept handler + char *class_name, *method_name; /* Pointers for class name and method name */ + size_t class_name_len, method_name_len; /* Lengths of class name and method name */ + zval *intercepted; /* Intercept handler */ ZEND_PARSE_PARAMETERS_START(3, 3) - Z_PARAM_STRING(class_name, class_name_len) // Parse class name parameter - Z_PARAM_STRING(method_name, method_name_len) // Parse method name parameter - Z_PARAM_OBJECT(intercepted) // Parse intercept handler parameter + Z_PARAM_STRING(class_name, class_name_len) /* Parse class name parameter */ + Z_PARAM_STRING(method_name, method_name_len) /* Parse method name parameter */ + Z_PARAM_OBJECT(intercepted) /* Parse intercept handler parameter */ ZEND_PARSE_PARAMETERS_END(); - intercept_info *new_info = ecalloc(1, sizeof(intercept_info)); // Allocate memory for new intercept information - if (!new_info) { // If memory allocation fails - rayaop_handle_error("Failed to allocate memory for intercept_info"); // Output error message - RETURN_FALSE; // Return false and end + php_rayaop_intercept_info *new_info = ecalloc(1, sizeof(php_rayaop_intercept_info)); /* Allocate memory for new intercept information */ + if (!new_info) { + /* If memory allocation fails */ + php_rayaop_handle_error("Failed to allocate memory for intercept_info"); /* Output error message */ + RETURN_FALSE; /* Return false and end */ } - new_info->class_name = zend_string_init(class_name, class_name_len, 0); // Initialize class name - new_info->method_name = zend_string_init(method_name, method_name_len, 0); // Initialize method name - ZVAL_COPY(&new_info->handler, intercepted); // Copy intercept handler + new_info->class_name = zend_string_init(class_name, class_name_len, 0); /* Initialize class name */ + new_info->method_name = zend_string_init(method_name, method_name_len, 0); /* Initialize method name */ + ZVAL_COPY(&new_info->handler, intercepted); /* Copy intercept handler */ char *key = NULL; - size_t key_len = spprintf(&key, 0, "%s::%s", class_name, method_name); // Generate intercept key + size_t key_len = spprintf(&key, 0, "%s::%s", class_name, method_name); /* Generate intercept key */ - if (zend_hash_str_update_ptr(RAYAOP_G(intercept_ht), key, key_len, new_info) == NULL) { // Add to hash table - hash_update_failed(new_info, key); // Execute error handling if addition fails - RETURN_FALSE; // Return false and end + if (zend_hash_str_update_ptr(RAYAOP_G(intercept_ht), key, key_len, new_info) == NULL) { + /* Add to hash table */ + php_rayaop_hash_update_failed(new_info, key); /* Execute error handling if addition fails */ +RETURN_FALSE; /* Return false and end */ } - efree(key); // Free memory for key - RAYAOP_DEBUG_PRINT("Successfully registered intercept info"); // Output debug information - RETURN_TRUE; // Return true and end + efree(key); /* Free memory for key */ + PHP_RAYAOP_DEBUG_PRINT("Successfully registered intercept info"); /* Output debug information */ + RETURN_TRUE; /* Return true and end */ } +/* }}} */ -// Interface definition +/* Interface definition */ zend_class_entry *ray_aop_method_interceptor_interface_ce; ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_ray_aop_method_interceptor_intercept, 0, 3, IS_MIXED, 0) - ZEND_ARG_TYPE_INFO(0, object, IS_OBJECT, 0) // 1st argument: object - ZEND_ARG_TYPE_INFO(0, method, IS_STRING, 0) // 2nd argument: method name - ZEND_ARG_TYPE_INFO(0, params, IS_ARRAY, 0) // 3rd argument: parameter array + ZEND_ARG_TYPE_INFO(0, object, IS_OBJECT, 0) /* 1st argument: object */ + ZEND_ARG_TYPE_INFO(0, method, IS_STRING, 0) /* 2nd argument: method name */ + ZEND_ARG_TYPE_INFO(0, params, IS_ARRAY, 0) /* 3rd argument: parameter array */ ZEND_END_ARG_INFO() static const zend_function_entry ray_aop_method_interceptor_interface_methods[] = { - ZEND_ABSTRACT_ME(Ray_Aop_MethodInterceptorInterface, intercept, arginfo_ray_aop_method_interceptor_intercept) // Define intercept method - PHP_FE_END // End of function entries + ZEND_ABSTRACT_ME(Ray_Aop_MethodInterceptorInterface, intercept, arginfo_ray_aop_method_interceptor_intercept) + /* Define intercept method */ + PHP_FE_END /* End of function entries */ }; -/** - * Extension initialization function - * - * @param INIT_FUNC_ARGS Initialization function arguments - * @return int Success or failure of initialization - */ -PHP_MINIT_FUNCTION(rayaop) -{ - RAYAOP_DEBUG_PRINT("PHP_MINIT_FUNCTION called"); // Output debug information +/* {{{ proto int PHP_MINIT_FUNCTION(rayaop) + Extension initialization function + + This function is called when the extension is loaded. It initializes the extension, + registers the interface, and sets up the custom execute function. + + @return int Returns SUCCESS on successful initialization +*/ +PHP_MINIT_FUNCTION(rayaop) { + PHP_RAYAOP_DEBUG_PRINT("PHP_MINIT_FUNCTION called"); /* Output debug information */ #ifdef ZTS - ts_allocate_id(&rayaop_globals_id, sizeof(zend_rayaop_globals), (ts_allocate_ctor) php_rayaop_init_globals, NULL); // Initialize global variables in thread-safe mode + ts_allocate_id(&rayaop_globals_id, sizeof(zend_rayaop_globals), (ts_allocate_ctor) php_rayaop_init_globals, NULL); /* Initialize global variables in thread-safe mode */ #else - php_rayaop_init_globals(&rayaop_globals); // Initialize global variables in non-thread-safe mode + php_rayaop_init_globals(&rayaop_globals); /* Initialize global variables in non-thread-safe mode */ +#endif + +#if PHP_RAYAOP_EXPERIMENTAL && !RAYAOP_QUIET + php_error_docref(NULL, E_NOTICE, "The Ray.Aop extension is experimental. Its functions may change or be removed in future releases."); #endif zend_class_entry ce; - INIT_CLASS_ENTRY(ce, "Ray\\Aop\\MethodInterceptorInterface", ray_aop_method_interceptor_interface_methods); // Initialize class entry - ray_aop_method_interceptor_interface_ce = zend_register_internal_interface(&ce); // Register interface + INIT_CLASS_ENTRY(ce, "Ray\\Aop\\MethodInterceptorInterface", ray_aop_method_interceptor_interface_methods); + /* Initialize class entry */ + ray_aop_method_interceptor_interface_ce = zend_register_internal_interface(&ce); /* Register interface */ -original_zend_execute_ex = zend_execute_ex; // Save the original zend_execute_ex function - zend_execute_ex = rayaop_zend_execute_ex; // Set the custom zend_execute_ex function + php_rayaop_original_execute_ex = zend_execute_ex; /* Save the original zend_execute_ex function */ + zend_execute_ex = php_rayaop_execute_ex; /* Set the custom zend_execute_ex function */ - RAYAOP_DEBUG_PRINT("RayAOP extension initialized"); // Output debug information - return SUCCESS; // Return success + PHP_RAYAOP_DEBUG_PRINT("RayAOP extension initialized"); /* Output debug information */ + return SUCCESS; /* Return success */ } - -/** - * Extension shutdown function - * - * @param SHUTDOWN_FUNC_ARGS Shutdown function arguments - * @return int Success or failure of shutdown - */ -PHP_MSHUTDOWN_FUNCTION(rayaop) -{ - RAYAOP_DEBUG_PRINT("RayAOP PHP_MSHUTDOWN_FUNCTION called"); // Output debug information - - zend_execute_ex = original_zend_execute_ex; // Restore the original zend_execute_ex function - original_zend_execute_ex = NULL; // Clear the saved pointer - - RAYAOP_DEBUG_PRINT("RayAOP PHP_MSHUTDOWN_FUNCTION shut down"); // Output debug information - return SUCCESS; // Return shutdown success +/* }}} */ + +/* {{{ proto int PHP_MSHUTDOWN_FUNCTION(rayaop) + Extension shutdown function + + This function is called when the extension is unloaded. It restores the original + execute function and performs any necessary cleanup. + + @return int Returns SUCCESS on successful shutdown +*/ +PHP_MSHUTDOWN_FUNCTION(rayaop) { + PHP_RAYAOP_DEBUG_PRINT("RayAOP PHP_MSHUTDOWN_FUNCTION called"); /* Output debug information */ + zend_execute_ex = php_rayaop_original_execute_ex; /* Restore the original zend_execute_ex function */ + php_rayaop_original_execute_ex = NULL; /* Clear the saved pointer */ + PHP_RAYAOP_DEBUG_PRINT("RayAOP PHP_MSHUTDOWN_FUNCTION shut down"); /* Output debug information */ + return SUCCESS; /* Return shutdown success */ } - -/** - * Initialization function at the start of a request - * - * @param INIT_FUNC_ARGS Initialization function arguments - * @return int Success or failure of initialization - */ -PHP_RINIT_FUNCTION(rayaop) -{ - RAYAOP_DEBUG_PRINT("PHP_RINIT_FUNCTION called"); // Output debug information - - if (RAYAOP_G(intercept_ht) == NULL) { // If intercept hash table is not initialized - ALLOC_HASHTABLE(RAYAOP_G(intercept_ht)); // Allocate memory for hash table - zend_hash_init(RAYAOP_G(intercept_ht), 8, NULL, rayaop_free_intercept_info, 0); // Initialize hash table +/* }}} */ + +/* {{{ proto int PHP_RINIT_FUNCTION(rayaop) + Request initialization function + + This function is called at the beginning of each request. It initializes + the intercept hash table for the current request. + + @return int Returns SUCCESS on successful initialization +*/ +PHP_RINIT_FUNCTION(rayaop) { + PHP_RAYAOP_DEBUG_PRINT("PHP_RINIT_FUNCTION called"); /* Output debug information */ + if (RAYAOP_G(intercept_ht) == NULL) { + /* If intercept hash table is not initialized */ + ALLOC_HASHTABLE(RAYAOP_G(intercept_ht)); /* Allocate memory for hash table */ + zend_hash_init(RAYAOP_G(intercept_ht), 8, NULL, php_rayaop_free_intercept_info, 0); /* Initialize hash table */ } - RAYAOP_G(is_intercepting) = 0; // Initialize intercept flag - - return SUCCESS; // Return success + RAYAOP_G(is_intercepting) = 0; /* Initialize intercept flag */ + return SUCCESS; /* Return success */ } - -/** - * Shutdown function at the end of a request - * - * @param SHUTDOWN_FUNC_ARGS Shutdown function arguments - * @return int Success or failure of shutdown - */ -PHP_RSHUTDOWN_FUNCTION(rayaop) -{ - RAYAOP_DEBUG_PRINT("RayAOP PHP_RSHUTDOWN_FUNCTION called"); // Output debug information - if (RAYAOP_G(intercept_ht)) { // If intercept hash table exists - zend_hash_destroy(RAYAOP_G(intercept_ht)); // Destroy hash table - FREE_HASHTABLE(RAYAOP_G(intercept_ht)); // Free memory for hash table - RAYAOP_G(intercept_ht) = NULL; // Set hash table pointer to NULL +/* }}} */ + +/* {{{ proto int PHP_RSHUTDOWN_FUNCTION(rayaop) + Request shutdown function + + This function is called at the end of each request. It cleans up the + intercept hash table and frees associated memory. + + @return int Returns SUCCESS on successful shutdown +*/ +PHP_RSHUTDOWN_FUNCTION(rayaop) { + PHP_RAYAOP_DEBUG_PRINT("RayAOP PHP_RSHUTDOWN_FUNCTION called"); /* Output debug information */ + if (RAYAOP_G(intercept_ht)) { + /* If intercept hash table exists */ + zend_hash_destroy(RAYAOP_G(intercept_ht)); /* Destroy hash table */ + FREE_HASHTABLE(RAYAOP_G(intercept_ht)); /* Free memory for hash table */ + RAYAOP_G(intercept_ht) = NULL; /* Set hash table pointer to NULL */ } - - RAYAOP_DEBUG_PRINT("RayAOP PHP_RSHUTDOWN_FUNCTION shut down"); // Output debug information - return SUCCESS; // Return shutdown success + PHP_RAYAOP_DEBUG_PRINT("RayAOP PHP_RSHUTDOWN_FUNCTION shut down"); /* Output debug information */ + return SUCCESS; /* Return shutdown success */ } - -/** - * Extension information display function - * - * @param ZEND_MODULE_INFO_FUNC_ARGS Information display function arguments - */ -PHP_MINFO_FUNCTION(rayaop) -{ - php_info_print_table_start(); // Start information table - php_info_print_table_header(2, "rayaop support", "enabled"); // Display table header - php_info_print_table_row(2, "Version", PHP_RAYAOP_VERSION); // Display version information - php_info_print_table_end(); // End information table +/* }}} */ + +/* {{{ proto void PHP_MINFO_FUNCTION(rayaop) + Extension information display function + + This function is called to display information about the extension in phpinfo(). +*/ +PHP_MINFO_FUNCTION(rayaop) { + php_info_print_table_start(); /* Start information table */ + php_info_print_table_header(2, "rayaop support", "enabled"); /* Display table header */ + php_info_print_table_row(2, "Version", PHP_RAYAOP_VERSION); /* Display version information */ + php_info_print_table_end(); /* End information table */ } +/* }}} */ -// For debugging: Function to dump intercept information #ifdef RAYAOP_DEBUG -/** - * Function to dump intercept information (for debugging) - */ -static void rayaop_dump_intercept_info(void) +/* {{{ proto void php_rayaop_dump_intercept_info(void) + Function to dump intercept information (for debugging) + + This function outputs debug information about the current state of the intercept hash table. +*/ +static void php_rayaop_dump_intercept_info(void) { - RAYAOP_DEBUG_PRINT("Dumping intercept information:"); // Output debug information - if (RAYAOP_G(intercept_ht)) { // If intercept hash table exists + PHP_RAYAOP_DEBUG_PRINT("Dumping intercept information:"); /* Output debug information */ + if (RAYAOP_G(intercept_ht)) { /* If intercept hash table exists */ zend_string *key; - intercept_info *info; - ZEND_HASH_FOREACH_STR_KEY_PTR(RAYAOP_G(intercept_ht), key, info) { // For each element in the hash table - if (key && info) { // If key and information exist - RAYAOP_DEBUG_PRINT("Key: %s", ZSTR_VAL(key)); // Output key - RAYAOP_DEBUG_PRINT(" Class: %s", ZSTR_VAL(info->class_name)); // Output class name - RAYAOP_DEBUG_PRINT(" Method: %s", ZSTR_VAL(info->method_name)); // Output method name - RAYAOP_DEBUG_PRINT(" Handler type: %d", Z_TYPE(info->handler)); // Output handler type + php_rayaop_intercept_info *info; + ZEND_HASH_FOREACH_STR_KEY_PTR(RAYAOP_G(intercept_ht), key, info) { /* For each element in the hash table */ + if (key && info) { /* If key and information exist */ + PHP_RAYAOP_DEBUG_PRINT("Key: %s", ZSTR_VAL(key)); /* Output key */ + PHP_RAYAOP_DEBUG_PRINT(" Class: %s", ZSTR_VAL(info->class_name)); /* Output class name */ + PHP_RAYAOP_DEBUG_PRINT(" Method: %s", ZSTR_VAL(info->method_name)); /* Output method name */ + PHP_RAYAOP_DEBUG_PRINT(" Handler type: %d", Z_TYPE(info->handler)); /* Output handler type */ } } ZEND_HASH_FOREACH_END(); - } else { // If intercept hash table does not exist - RAYAOP_DEBUG_PRINT("Intercept hash table is not initialized"); // Output that it's not initialized + } else { /* If intercept hash table does not exist */ + PHP_RAYAOP_DEBUG_PRINT("Intercept hash table is not initialized"); /* Output that it's not initialized */ } } +/* }}} */ #endif -// Definition of functions provided by the extension +/* Definition of functions provided by the extension */ static const zend_function_entry rayaop_functions[] = { - PHP_FE(method_intercept, arginfo_method_intercept) // Register method_intercept function - PHP_FE_END // End of function entries + PHP_FE(method_intercept, arginfo_method_intercept) /* Register method_intercept function */ + PHP_FE_END /* End of function entries */ }; -// Extension module entry +/* Extension module entry */ zend_module_entry rayaop_module_entry = { STANDARD_MODULE_HEADER, - "rayaop", // Extension name - rayaop_functions, // Functions provided by the extension - PHP_MINIT(rayaop), // Extension initialization function - PHP_MSHUTDOWN(rayaop), // Extension shutdown function - PHP_RINIT(rayaop), // Function at request start - PHP_RSHUTDOWN(rayaop), // Function at request end - PHP_MINFO(rayaop), // Extension information display function - PHP_RAYAOP_VERSION, // Extension version + "rayaop", /* Extension name */ + rayaop_functions, /* Functions provided by the extension */ + PHP_MINIT(rayaop), /* Extension initialization function */ + PHP_MSHUTDOWN(rayaop), /* Extension shutdown function */ + PHP_RINIT(rayaop), /* Function at request start */ + PHP_RSHUTDOWN(rayaop), /* Function at request end */ + PHP_MINFO(rayaop), /* Extension information display function */ + PHP_RAYAOP_VERSION, /* Extension version */ STANDARD_MODULE_PROPERTIES }; #ifdef COMPILE_DL_RAYAOP -ZEND_GET_MODULE(rayaop) // Function to get module for dynamic loading -#endif \ No newline at end of file +ZEND_GET_MODULE(rayaop) /* Function to get module for dynamic loading */ +#endif