6 changed files with 0 additions and 995 deletions
-
2ext/overload/CREDITS
-
94ext/overload/README
-
16ext/overload/config.m4
-
708ext/overload/overload.c
-
108ext/overload/overload.dsp
-
67ext/overload/php_overload.h
@ -1,2 +0,0 @@ |
|||
User-space object overloading |
|||
Andrei Zmievski |
|||
@ -1,94 +0,0 @@ |
|||
The purpose of this extension is to allow user-space overloading of object |
|||
property access and method calls. It has only one function, overload() which |
|||
takes the name of the class that should have this functionality enabled. But |
|||
the class has to define appropriate methods if it wants to have this |
|||
functionality: __get(), __set(), and __call(). So, overloading can be |
|||
selective. |
|||
|
|||
Inside each handler the overloading is disabled so you can access object |
|||
properties normally. |
|||
|
|||
|
|||
Usage |
|||
----- |
|||
<?php |
|||
|
|||
class OO { |
|||
var $a = 111; |
|||
var $elem = array('b' => 9, 'c' => 42); |
|||
|
|||
function OO($aval = null) |
|||
{ |
|||
$this->a = $aval; |
|||
} |
|||
|
|||
function __get($prop_name, &$prop_value) |
|||
{ |
|||
if (isset($this->elem[$prop_name])) { |
|||
$prop_value = $this->elem[$prop_name]; |
|||
return true; |
|||
} else |
|||
return false; |
|||
} |
|||
|
|||
function __set($prop_name, $prop_value) |
|||
{ |
|||
$this->elem[$prop_name] = $prop_value; |
|||
return true; |
|||
} |
|||
|
|||
function __call($method, $args, &$return_value) |
|||
{ |
|||
print '-- OO::' . $method . "() was called.--\n"; |
|||
$return_value = call_user_func_array(array(&$this, 'my_' . $method), $args); |
|||
return true; |
|||
} |
|||
|
|||
function my_whatever($f1, $f2, $f3) |
|||
{ |
|||
var_dump($f1, $f2, $f3); |
|||
return $f1 + $f2; |
|||
} |
|||
|
|||
function __get_foo(&$prop_value) |
|||
{ |
|||
$prop_value = 'Bam bam bam!'; |
|||
return true; |
|||
} |
|||
|
|||
function __set_count($prop_value) |
|||
{ |
|||
if ($prop_value >= 1 && $prop_value <= 100) { |
|||
$this->elem['COUNT'] = $prop_value; |
|||
return true; |
|||
} else |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
overload('OO'); |
|||
|
|||
$o = new OO; |
|||
print "\$o->a: $o->a\n"; |
|||
print "\$o->b: $o->b\n"; |
|||
print "\$o->c: $o->c\n"; |
|||
print "\$o->d: $o->d\n"; |
|||
|
|||
$val = new stdclass; |
|||
$val->prop = 555; |
|||
|
|||
$o->a = array($val); |
|||
var_dump($o->a[0]->prop); |
|||
|
|||
var_dump($o->whatever(1, 2, 'a')); |
|||
|
|||
var_dump($o->foo); |
|||
$o->count = 100; |
|||
var_dump($o->COUNT); |
|||
|
|||
?> |
|||
|
|||
What doesn't work |
|||
----------------- |
|||
Invoking original overloading handlers, if the class had any. |
|||
__set() only works to one level of property access, no chains yet. |
|||
@ -1,16 +0,0 @@ |
|||
dnl |
|||
dnl $Id$ |
|||
dnl |
|||
|
|||
PHP_ARG_ENABLE(overload,whether to enable user-space object overloading support, |
|||
[ --disable-overload Disable user-space object overloading support.], yes) |
|||
|
|||
if test "$PHP_OVERLOAD" != "no"; then |
|||
if test -f $php_abs_top_srcdir/Zend/zend_objects.h; then |
|||
AC_MSG_CHECKING(for overload) |
|||
AC_MSG_RESULT(not needed with ZendEngine 2) |
|||
else |
|||
AC_DEFINE(HAVE_OVERLOAD, 1, [ ]) |
|||
PHP_NEW_EXTENSION(overload, overload.c, $ext_shared) |
|||
fi |
|||
fi |
|||
@ -1,708 +0,0 @@ |
|||
/* |
|||
+----------------------------------------------------------------------+ |
|||
| PHP Version 4 | |
|||
+----------------------------------------------------------------------+ |
|||
| Copyright (c) 1997-2003 The PHP Group | |
|||
+----------------------------------------------------------------------+ |
|||
| This source file is subject to version 2.02 of the PHP license, | |
|||
| that is bundled with this package in the file LICENSE, and is | |
|||
| available at through the world-wide-web at | |
|||
| http://www.php.net/license/2_02.txt. | |
|||
| If you did not receive a copy of the PHP license and are unable to | |
|||
| obtain it through the world-wide-web, please send a note to | |
|||
| license@php.net so we can mail you a copy immediately. | |
|||
+----------------------------------------------------------------------+ |
|||
| Author: Andrei Zmievski <andrei@php.net> | |
|||
+----------------------------------------------------------------------+ |
|||
*/ |
|||
|
|||
/* |
|||
* TODO: |
|||
* + provide a way for user to enable/disabling overloading of get/set/call |
|||
* individually |
|||
* - call original overloaded handlers if necessary |
|||
* + use local copy of CE with NULL'ed out handler when calling object's |
|||
* overloaded function |
|||
* - handle both OE_IS_OBJECT and OE_IS_ARRAY in the whole chain |
|||
* + see how to fix the issue of object trying to set its own property inside |
|||
* the handler |
|||
* + check if function exists in function table, then call it, otherwise |
|||
* call handler (aka AUTOLOAD in Perl) |
|||
* + should it check for existing properties first before calling __get/__set: |
|||
* yes |
|||
* + turn off all overloading handlers on a call to a handler |
|||
* - pass array overloading info on to handlers? |
|||
* - add unoverload() function |
|||
*/ |
|||
|
|||
#ifdef HAVE_CONFIG_H |
|||
#include "config.h" |
|||
#endif |
|||
|
|||
#include "php.h" |
|||
#include "php_ini.h" |
|||
#include "ext/standard/info.h" |
|||
#include "php_overload.h" |
|||
|
|||
#ifndef ZEND_ENGINE_2 |
|||
#if HAVE_OVERLOAD |
|||
|
|||
#define GET_HANDLER "__get" |
|||
#define SET_HANDLER "__set" |
|||
#define CALL_HANDLER "__call" |
|||
|
|||
#define DISABLE_HANDLERS(ce) \ |
|||
(ce).handle_property_get = NULL; \ |
|||
(ce).handle_property_set = NULL; \ |
|||
(ce).handle_function_call = NULL; |
|||
|
|||
typedef struct _oo_class_data { |
|||
void (*handle_function_call)(INTERNAL_FUNCTION_PARAMETERS, zend_property_reference *property_reference); |
|||
zval (*handle_property_get)(zend_property_reference *property_reference); |
|||
int (*handle_property_set)(zend_property_reference *property_reference, zval *value); |
|||
HashTable getters; |
|||
HashTable setters; |
|||
} oo_class_data; |
|||
|
|||
ZEND_DECLARE_MODULE_GLOBALS(overload) |
|||
|
|||
function_entry overload_functions[] = { |
|||
PHP_FE(overload, NULL) |
|||
{NULL, NULL, NULL} |
|||
}; |
|||
|
|||
zend_module_entry overload_module_entry = { |
|||
STANDARD_MODULE_HEADER, |
|||
"overload", |
|||
overload_functions, |
|||
PHP_MINIT(overload), |
|||
PHP_MSHUTDOWN(overload), |
|||
NULL, |
|||
PHP_RSHUTDOWN(overload), |
|||
PHP_MINFO(overload), |
|||
NO_VERSION_YET, |
|||
STANDARD_MODULE_PROPERTIES |
|||
}; |
|||
|
|||
#ifdef COMPILE_DL_OVERLOAD |
|||
ZEND_GET_MODULE(overload) |
|||
#endif |
|||
|
|||
static void overloaded_class_dtor(oo_class_data *oo_data) |
|||
{ |
|||
zend_hash_destroy(&oo_data->getters); |
|||
zend_hash_destroy(&oo_data->setters); |
|||
} |
|||
|
|||
/* {{{ php_overload_init_globals */ |
|||
static void php_overload_init_globals(zend_overload_globals *overload_globals TSRMLS_DC) |
|||
{ |
|||
zend_hash_init(&overload_globals->overloaded_classes, 10, NULL, |
|||
(dtor_func_t)overloaded_class_dtor, 1); |
|||
} |
|||
/* }}} */ |
|||
|
|||
/* {{{ php_overload_destroy_globals */ |
|||
static void php_overload_destroy_globals(zend_overload_globals *overload_globals TSRMLS_DC) |
|||
{ |
|||
zend_hash_destroy(&overload_globals->overloaded_classes); |
|||
} |
|||
/* }}} */ |
|||
|
|||
/* {{{ PHP_MINIT_FUNCTION(overload) */ |
|||
PHP_MINIT_FUNCTION(overload) |
|||
{ |
|||
ZEND_INIT_MODULE_GLOBALS(overload, php_overload_init_globals, php_overload_destroy_globals); |
|||
|
|||
/* If you have INI entries, uncomment these lines |
|||
REGISTER_INI_ENTRIES(); |
|||
*/ |
|||
return SUCCESS; |
|||
} |
|||
/* }}} */ |
|||
|
|||
/* {{{ PHP_MSHUTDOWN_FUNCTION(overload) */ |
|||
PHP_MSHUTDOWN_FUNCTION(overload) |
|||
{ |
|||
#ifdef ZTS |
|||
ts_free_id(overload_globals_id); |
|||
#else |
|||
php_overload_destroy_globals(&overload_globals TSRMLS_CC); |
|||
#endif |
|||
|
|||
return SUCCESS; |
|||
} |
|||
/* }}} */ |
|||
|
|||
/* {{{ PHP_RSHUTDOWN_FUNCTION(overload) */ |
|||
PHP_RSHUTDOWN_FUNCTION(overload) |
|||
{ |
|||
zend_hash_clean(&OOG(overloaded_classes)); |
|||
|
|||
return SUCCESS; |
|||
} |
|||
/* }}} */ |
|||
|
|||
/* {{{ PHP_MINFO_FUNCTION */ |
|||
PHP_MINFO_FUNCTION(overload) |
|||
{ |
|||
php_info_print_table_start(); |
|||
php_info_print_table_row(2, "User-Space Object Overloading Support", "enabled"); |
|||
php_info_print_table_end(); |
|||
|
|||
/* Remove comments if you have entries in php.ini |
|||
DISPLAY_INI_ENTRIES(); |
|||
*/ |
|||
} |
|||
/* }}} */ |
|||
|
|||
/* |
|||
* In all three handlers, we save the original CE of the object, and replace it |
|||
* with a temporary one that has all handlers turned off. This is to avoid |
|||
* recursive calls to our handlers. We can't simply set a handler to NULL on the |
|||
* original CE, as that would disable overloading on other objects of the same |
|||
* class. After invoking the callback we restore the object's CE. |
|||
*/ |
|||
|
|||
/* {{{ static int call_get_handler() */ |
|||
static int call_get_handler(zval *object, zval *prop_name, zval **prop_value TSRMLS_DC) |
|||
{ |
|||
int call_result; |
|||
zend_class_entry temp_ce, *orig_ce; |
|||
zval result, *result_ptr = &result; |
|||
zval get_handler; |
|||
zval **args[2]; |
|||
zval *retval = NULL; |
|||
char *lcase_prop_name; |
|||
zval **accessor_name; |
|||
oo_class_data *oo_data; |
|||
|
|||
if (zend_hash_index_find(&OOG(overloaded_classes), (long)Z_OBJCE_P(object), (void**)&oo_data) == FAILURE) { |
|||
php_error(E_WARNING, "internal problem trying to get property"); |
|||
return 0; |
|||
} |
|||
|
|||
temp_ce = *Z_OBJCE_P(object); |
|||
DISABLE_HANDLERS(temp_ce); |
|||
orig_ce = Z_OBJCE_P(object); |
|||
Z_OBJ_P(object)->ce = &temp_ce; |
|||
|
|||
result_ptr->is_ref = 1; |
|||
result_ptr->refcount = 1; |
|||
ZVAL_NULL(result_ptr); |
|||
|
|||
lcase_prop_name = estrndup(Z_STRVAL_P(prop_name), Z_STRLEN_P(prop_name)); |
|||
zend_str_tolower(lcase_prop_name, Z_STRLEN_P(prop_name)); |
|||
if (zend_hash_find(&oo_data->getters, lcase_prop_name, |
|||
Z_STRLEN_P(prop_name)+1, (void **)&accessor_name) == SUCCESS) { |
|||
efree(lcase_prop_name); |
|||
args[0] = &result_ptr; |
|||
|
|||
call_result = call_user_function_ex(NULL, |
|||
&object, |
|||
*accessor_name, |
|||
&retval, |
|||
1, args, |
|||
0, NULL TSRMLS_CC); |
|||
Z_OBJ_P(object)->ce = orig_ce; |
|||
|
|||
if (call_result == FAILURE || !retval) { |
|||
php_error(E_WARNING, "unable to call %s::" GET_HANDLER "_%s() handler", Z_OBJCE_P(object)->name, Z_STRVAL_P(prop_name)); |
|||
return 0; |
|||
} |
|||
} else { |
|||
efree(lcase_prop_name); |
|||
ZVAL_STRINGL(&get_handler, GET_HANDLER, sizeof(GET_HANDLER)-1, 0); |
|||
args[0] = &prop_name; |
|||
args[1] = &result_ptr; |
|||
|
|||
call_result = call_user_function_ex(NULL, |
|||
&object, |
|||
&get_handler, |
|||
&retval, |
|||
2, args, |
|||
0, NULL TSRMLS_CC); |
|||
Z_OBJ_P(object)->ce = orig_ce; |
|||
|
|||
if (call_result == FAILURE || !retval) { |
|||
php_error(E_WARNING, "unable to call %s::" GET_HANDLER "() handler", Z_OBJCE_P(object)->name); |
|||
return 0; |
|||
} |
|||
} |
|||
|
|||
if (zval_is_true(retval)) { |
|||
REPLACE_ZVAL_VALUE(prop_value, result_ptr, 0); |
|||
zval_ptr_dtor(&retval); |
|||
return 1; |
|||
} |
|||
|
|||
zval_ptr_dtor(&retval); |
|||
zval_dtor(result_ptr); |
|||
|
|||
if (!oo_data->handle_property_get) { |
|||
return 0; |
|||
} |
|||
|
|||
/* TODO: call original OO handler */ |
|||
|
|||
return 0; |
|||
} |
|||
/* }}} */ |
|||
|
|||
/* {{{ static int call_set_handler() */ |
|||
int call_set_handler(zval *object, zval *prop_name, zval *value TSRMLS_DC) |
|||
{ |
|||
int call_result; |
|||
zend_class_entry temp_ce, *orig_ce; |
|||
zval set_handler; |
|||
zval *value_copy; |
|||
zval **args[2]; |
|||
zval *retval = NULL; |
|||
char *lcase_prop_name; |
|||
zval **accessor_name; |
|||
oo_class_data *oo_data; |
|||
|
|||
if (zend_hash_index_find(&OOG(overloaded_classes), (long)Z_OBJCE_P(object), (void**)&oo_data) == FAILURE) { |
|||
php_error(E_WARNING, "internal problem trying to set property"); |
|||
return 0; |
|||
} |
|||
|
|||
temp_ce = *Z_OBJCE_P(object); |
|||
DISABLE_HANDLERS(temp_ce); |
|||
orig_ce = Z_OBJCE_P(object); |
|||
Z_OBJ_P(object)->ce = &temp_ce; |
|||
|
|||
if (value->refcount == 0) { |
|||
MAKE_STD_ZVAL(value_copy); |
|||
*value_copy = *value; |
|||
zval_copy_ctor(value_copy); |
|||
value = value_copy; |
|||
} |
|||
|
|||
lcase_prop_name = estrndup(Z_STRVAL_P(prop_name), Z_STRLEN_P(prop_name)); |
|||
zend_str_tolower(lcase_prop_name, Z_STRLEN_P(prop_name)); |
|||
if (zend_hash_find(&oo_data->setters, lcase_prop_name, |
|||
Z_STRLEN_P(prop_name)+1, (void **)&accessor_name) == SUCCESS) { |
|||
efree(lcase_prop_name); |
|||
args[0] = &value; |
|||
|
|||
call_result = call_user_function_ex(NULL, |
|||
&object, |
|||
*accessor_name, |
|||
&retval, |
|||
1, args, |
|||
0, NULL TSRMLS_CC); |
|||
Z_OBJ_P(object)->ce = orig_ce; |
|||
|
|||
if (call_result == FAILURE || !retval) { |
|||
php_error(E_WARNING, "unable to call %s::" SET_HANDLER "_%s() handler", Z_OBJCE_P(object)->name, Z_STRVAL_P(prop_name)); |
|||
return 0; |
|||
} |
|||
} else { |
|||
efree(lcase_prop_name); |
|||
ZVAL_STRINGL(&set_handler, SET_HANDLER, sizeof(SET_HANDLER)-1, 0); |
|||
args[0] = &prop_name; |
|||
args[1] = &value; |
|||
|
|||
call_result = call_user_function_ex(NULL, |
|||
&object, |
|||
&set_handler, |
|||
&retval, |
|||
2, args, |
|||
0, NULL TSRMLS_CC); |
|||
Z_OBJ_P(object)->ce = orig_ce; |
|||
|
|||
if (call_result == FAILURE || !retval) { |
|||
php_error(E_WARNING, "unable to call %s::" SET_HANDLER "() handler", orig_ce->name); |
|||
return 0; |
|||
} |
|||
} |
|||
|
|||
if (zval_is_true(retval)) { |
|||
zval_ptr_dtor(&retval); |
|||
return 1; |
|||
} |
|||
|
|||
zval_ptr_dtor(&retval); |
|||
|
|||
if (!oo_data->handle_property_set) { |
|||
return 0; |
|||
} |
|||
|
|||
/* TODO: call original OO handler */ |
|||
|
|||
return 0; |
|||
|
|||
} |
|||
/* }}} */ |
|||
|
|||
#define CLEANUP_OO_CHAIN() { \ |
|||
for (; element; element=element->next) { \ |
|||
zval_dtor(&((zend_overloaded_element *)element->data)->element); \ |
|||
} \ |
|||
} \ |
|||
|
|||
/* {{{ zval overload_get_property() */ |
|||
static zval overload_get_property(zend_property_reference *property_reference) |
|||
{ |
|||
zval result; |
|||
zval *result_ptr = &result; |
|||
zend_overloaded_element *overloaded_property; |
|||
zend_llist_element *element; |
|||
zval object = *property_reference->object; |
|||
zval **real_prop; |
|||
int got_prop = 0; |
|||
TSRMLS_FETCH(); |
|||
|
|||
INIT_PZVAL(result_ptr); |
|||
|
|||
for (element=property_reference->elements_list->head; element; element=element->next) { |
|||
overloaded_property = (zend_overloaded_element *) element->data; |
|||
ZVAL_NULL(result_ptr); |
|||
|
|||
if (Z_TYPE_P(overloaded_property) == OE_IS_OBJECT) { |
|||
/* Trying to access a property on a non-object. */ |
|||
if (Z_TYPE(object) != IS_OBJECT) { |
|||
CLEANUP_OO_CHAIN(); |
|||
if (got_prop) |
|||
zval_dtor(&object); |
|||
return result; |
|||
} |
|||
|
|||
if (zend_hash_find(Z_OBJPROP(object), |
|||
Z_STRVAL(overloaded_property->element), |
|||
Z_STRLEN(overloaded_property->element)+1, |
|||
(void **)&real_prop) == SUCCESS) { |
|||
result = **real_prop; |
|||
/* printf("is_ref: %d, refcount: %d\n", (*real_prop)->is_ref, (*real_prop)->refcount); */ |
|||
/* REPLACE_ZVAL_VALUE(&result_ptr, *real_prop, 1); */ |
|||
} else if (Z_OBJCE(object)->handle_property_get == overload_get_property && |
|||
call_get_handler(&object, |
|||
&overloaded_property->element, |
|||
&result_ptr TSRMLS_CC)) { |
|||
got_prop = 1; |
|||
} else { |
|||
php_error(E_NOTICE, "Undefined property: %s", Z_STRVAL(overloaded_property->element)); |
|||
CLEANUP_OO_CHAIN(); |
|||
if (got_prop) |
|||
zval_dtor(&object); |
|||
return result; |
|||
} |
|||
} else if (Z_TYPE_P(overloaded_property) == OE_IS_ARRAY) { |
|||
/* Trying to access index on a non-array. */ |
|||
if (Z_TYPE(object) != IS_ARRAY) { |
|||
CLEANUP_OO_CHAIN(); |
|||
if (got_prop) |
|||
zval_dtor(&object); |
|||
return result; |
|||
} |
|||
|
|||
if (Z_TYPE(overloaded_property->element) == IS_STRING) { |
|||
if (zend_hash_find(Z_ARRVAL(object), |
|||
Z_STRVAL(overloaded_property->element), |
|||
Z_STRLEN(overloaded_property->element)+1, |
|||
(void **)&real_prop) == FAILURE) { |
|||
CLEANUP_OO_CHAIN(); |
|||
if (got_prop) |
|||
zval_dtor(&object); |
|||
return result; |
|||
} |
|||
} else if (Z_TYPE(overloaded_property->element) == IS_LONG) { |
|||
if (zend_hash_index_find(Z_ARRVAL(object), |
|||
Z_LVAL(overloaded_property->element), |
|||
(void **)&real_prop) == FAILURE) { |
|||
CLEANUP_OO_CHAIN(); |
|||
if (got_prop) |
|||
zval_dtor(&object); |
|||
return result; |
|||
} |
|||
} |
|||
|
|||
result = **real_prop; |
|||
} |
|||
|
|||
zval_dtor(&overloaded_property->element); |
|||
/* printf("got_prop: %d\n", got_prop); */ |
|||
if (element != property_reference->elements_list->head && got_prop) { |
|||
zval_dtor(&object); |
|||
got_prop = 0; |
|||
} |
|||
|
|||
object = result; |
|||
} |
|||
|
|||
if (!got_prop) |
|||
zval_copy_ctor(&result); |
|||
|
|||
return result; |
|||
} |
|||
/* }}} */ |
|||
|
|||
/* {{{ int overload_set_property() */ |
|||
static int overload_set_property(zend_property_reference *property_reference, zval *value) |
|||
{ |
|||
zval result; |
|||
zval *result_ptr = &result; |
|||
zend_overloaded_element *overloaded_property; |
|||
zend_llist_element *element; |
|||
zval **object = &property_reference->object; |
|||
TSRMLS_FETCH(); |
|||
|
|||
for (element=property_reference->elements_list->head; element; element=element->next) { |
|||
overloaded_property = (zend_overloaded_element *) element->data; |
|||
ZVAL_NULL(result_ptr); |
|||
|
|||
if (Z_TYPE_P(overloaded_property) == OE_IS_OBJECT) { |
|||
/* Trying to access a property on a non-object. */ |
|||
if (Z_TYPE_PP(object) != IS_OBJECT) { |
|||
CLEANUP_OO_CHAIN(); |
|||
return FAILURE; |
|||
} |
|||
|
|||
if (zend_hash_find(Z_OBJPROP_PP(object), |
|||
Z_STRVAL(overloaded_property->element), |
|||
Z_STRLEN(overloaded_property->element)+1, |
|||
(void **)&object) == FAILURE) { |
|||
|
|||
if (element == property_reference->elements_list->tail) { |
|||
if (Z_OBJCE_PP(object)->handle_property_set == overload_set_property && |
|||
call_set_handler(*object, |
|||
&overloaded_property->element, |
|||
value TSRMLS_CC)) { |
|||
CLEANUP_OO_CHAIN(); |
|||
return SUCCESS; |
|||
} else { |
|||
php_error(E_WARNING, "Unable to set property: %s", Z_STRVAL(overloaded_property->element)); |
|||
CLEANUP_OO_CHAIN(); |
|||
return FAILURE; |
|||
} |
|||
} |
|||
|
|||
if (Z_OBJCE_PP(object)->handle_property_get == overload_get_property && |
|||
call_get_handler(*object, |
|||
&overloaded_property->element, |
|||
&result_ptr TSRMLS_CC)) { |
|||
object = &result_ptr; |
|||
} else { |
|||
php_error(E_NOTICE, "Undefined property: %s", Z_STRVAL(overloaded_property->element)); |
|||
CLEANUP_OO_CHAIN(); |
|||
return FAILURE; |
|||
} |
|||
} |
|||
} else if (Z_TYPE_P(overloaded_property) == OE_IS_ARRAY) { |
|||
} |
|||
|
|||
zval_dtor(&overloaded_property->element); |
|||
} |
|||
|
|||
/* printf("value is_ref: %d, refcount: %d\n", value->is_ref, value->refcount); */ |
|||
REPLACE_ZVAL_VALUE(object, value, 1); |
|||
/* printf("object is_ref: %d, refcount: %d\n", (*object)->is_ref, (*object)->refcount); */ |
|||
|
|||
return SUCCESS; |
|||
} |
|||
/* }}} */ |
|||
|
|||
/* {{{ void overload_call_method() */ |
|||
static void overload_call_method(INTERNAL_FUNCTION_PARAMETERS, zend_property_reference *property_reference) |
|||
{ |
|||
zval ***args; |
|||
zval *retval = NULL; |
|||
int call_result; |
|||
zend_bool use_call_handler = 1; |
|||
zval *object = property_reference->object; |
|||
zval call_handler, method_name, *method_name_ptr = &method_name; |
|||
zend_overloaded_element *method = (zend_overloaded_element *)property_reference->elements_list->tail->data; |
|||
|
|||
/* |
|||
* We don't use the call handler if the invoked method exists in object's |
|||
* method table. |
|||
*/ |
|||
if (zend_hash_exists(&Z_OBJCE_P(object)->function_table, |
|||
Z_STRVAL(method->element), |
|||
Z_STRLEN(method->element) + 1)) { |
|||
use_call_handler = 0; |
|||
} |
|||
|
|||
args = (zval ***)emalloc(ZEND_NUM_ARGS() * sizeof(zval **)); |
|||
|
|||
if (zend_get_parameters_array_ex(ZEND_NUM_ARGS(), args) == FAILURE) { |
|||
efree(args); |
|||
php_error(E_WARNING, "unable to obtain arguments"); |
|||
return; |
|||
} |
|||
|
|||
if (use_call_handler) { |
|||
zval **handler_args[3]; |
|||
zval *arg_array; |
|||
zval result, *result_ptr = &result; |
|||
zend_class_entry temp_ce, *orig_ce; |
|||
int i; |
|||
|
|||
temp_ce = *Z_OBJCE_P(object); |
|||
DISABLE_HANDLERS(temp_ce); |
|||
orig_ce = Z_OBJCE_P(object); |
|||
Z_OBJ_P(object)->ce = &temp_ce; |
|||
|
|||
ZVAL_STRINGL(&call_handler, CALL_HANDLER, sizeof(CALL_HANDLER)-1, 0); |
|||
ZVAL_STRINGL(&method_name, Z_STRVAL(method->element), Z_STRLEN(method->element), 0); |
|||
INIT_PZVAL(&call_handler); |
|||
INIT_PZVAL(method_name_ptr); |
|||
|
|||
MAKE_STD_ZVAL(arg_array); |
|||
array_init(arg_array); |
|||
for (i = 0; i < ZEND_NUM_ARGS(); i++) { |
|||
zval_add_ref(args[i]); |
|||
add_next_index_zval(arg_array, *args[i]); |
|||
} |
|||
|
|||
result_ptr->is_ref = 1; |
|||
result_ptr->refcount = 1; |
|||
ZVAL_NULL(result_ptr); |
|||
|
|||
handler_args[0] = &method_name_ptr; |
|||
handler_args[1] = &arg_array; |
|||
handler_args[2] = &result_ptr; |
|||
call_result = call_user_function_ex(NULL, |
|||
&object, |
|||
&call_handler, |
|||
&retval, |
|||
3, handler_args, |
|||
0, NULL TSRMLS_CC); |
|||
Z_OBJ_P(object)->ce = orig_ce; |
|||
zval_ptr_dtor(&arg_array); |
|||
|
|||
if (call_result == FAILURE || !retval) { |
|||
efree(args); |
|||
zval_dtor(result_ptr); |
|||
php_error(E_WARNING, "unable to call %s::" CALL_HANDLER "() handler", Z_OBJCE_P(object)->name); |
|||
return; |
|||
} |
|||
|
|||
if (zval_is_true(retval)) { |
|||
*return_value = *result_ptr; |
|||
INIT_PZVAL(return_value); |
|||
} else { |
|||
zval_dtor(result_ptr); |
|||
php_error(E_WARNING, "Call to undefined method %s::%s()", Z_OBJCE_P(object)->name, Z_STRVAL(method_name)); |
|||
} |
|||
zval_ptr_dtor(&retval); |
|||
} else { |
|||
ZVAL_STRINGL(&call_handler, Z_STRVAL(method->element), Z_STRLEN(method->element), 0); |
|||
call_result = call_user_function_ex(NULL, |
|||
&object, |
|||
&call_handler, |
|||
&retval, |
|||
ZEND_NUM_ARGS(), args, |
|||
0, NULL TSRMLS_CC); |
|||
|
|||
if (call_result == FAILURE || !retval) { |
|||
efree(args); |
|||
php_error(E_WARNING, "unable to call %s::%s() method", Z_OBJCE_P(object)->name, Z_STRVAL(method->element)); |
|||
return; |
|||
} |
|||
|
|||
return_value->value = retval->value; |
|||
zval_copy_ctor(return_value); |
|||
zval_ptr_dtor(&retval); |
|||
} |
|||
|
|||
efree(args); |
|||
zval_dtor(&method->element); |
|||
} |
|||
/* }}} */ |
|||
|
|||
/* {{{ static int locate_accessors() */ |
|||
static int locate_accessors(zend_function *method, oo_class_data *oo_data TSRMLS_DC) |
|||
{ |
|||
zval *accessor_name; |
|||
char *function_name = method->common.function_name; |
|||
int function_name_len = strlen(method->common.function_name); |
|||
|
|||
if (!strncmp(function_name, GET_HANDLER "_", sizeof(GET_HANDLER "_")-1)) { |
|||
MAKE_STD_ZVAL(accessor_name); |
|||
ZVAL_STRINGL(accessor_name, function_name, function_name_len, 1); |
|||
zend_hash_update(&oo_data->getters, |
|||
function_name + sizeof(GET_HANDLER "_") - 1, |
|||
function_name_len - sizeof(GET_HANDLER "_") + 2, |
|||
(void *)&accessor_name, sizeof(zval *), NULL); |
|||
|
|||
} else if (!strncmp(function_name, SET_HANDLER "_", sizeof(SET_HANDLER "_")-1)) { |
|||
MAKE_STD_ZVAL(accessor_name); |
|||
ZVAL_STRINGL(accessor_name, function_name, function_name_len, 1); |
|||
zend_hash_update(&oo_data->setters, |
|||
function_name + sizeof(SET_HANDLER "_") - 1, |
|||
function_name_len - sizeof(SET_HANDLER "_") + 2, |
|||
(void *)&accessor_name, sizeof(zval *), NULL); |
|||
} |
|||
|
|||
return 0; |
|||
} |
|||
/* }}} */ |
|||
|
|||
/* {{{ proto void overload(string class_entry) |
|||
Enables property and method call overloading for a class. */ |
|||
PHP_FUNCTION(overload) |
|||
{ |
|||
char *class_entry = NULL; |
|||
int argc = ZEND_NUM_ARGS(); |
|||
int class_entry_len; |
|||
zend_class_entry *ce = NULL; |
|||
oo_class_data oo_data; |
|||
|
|||
if (zend_parse_parameters(argc TSRMLS_CC, "s/", &class_entry, &class_entry_len) == FAILURE) |
|||
return; |
|||
|
|||
zend_str_tolower(class_entry, class_entry_len); |
|||
if (zend_hash_find(EG(class_table), class_entry, class_entry_len+1, (void**)&ce) == FAILURE) { |
|||
php_error(E_WARNING, "%s() was unable to locate class '%s'", get_active_function_name(TSRMLS_C), class_entry); |
|||
RETURN_FALSE; |
|||
} |
|||
|
|||
/* Check if the handlers have already been installed for this class. */ |
|||
if (zend_hash_index_exists(&OOG(overloaded_classes), (long)ce)) { |
|||
RETURN_TRUE; |
|||
} |
|||
|
|||
zend_hash_init(&oo_data.getters, 10, NULL, ZVAL_PTR_DTOR, 0); |
|||
zend_hash_init(&oo_data.setters, 10, NULL, ZVAL_PTR_DTOR, 0); |
|||
|
|||
zend_hash_apply_with_argument(&ce->function_table, (apply_func_arg_t)locate_accessors, (void *)&oo_data TSRMLS_CC); |
|||
|
|||
if (zend_hash_exists(&ce->function_table, GET_HANDLER, sizeof(GET_HANDLER)) || |
|||
zend_hash_num_elements(&oo_data.getters)) { |
|||
oo_data.handle_property_get = ce->handle_property_get; |
|||
ce->handle_property_get = overload_get_property; |
|||
} else |
|||
oo_data.handle_property_get = NULL; |
|||
|
|||
if (zend_hash_exists(&ce->function_table, SET_HANDLER, sizeof(SET_HANDLER)) || |
|||
zend_hash_num_elements(&oo_data.setters)) { |
|||
oo_data.handle_property_set = ce->handle_property_set; |
|||
ce->handle_property_set = overload_set_property; |
|||
} else |
|||
oo_data.handle_property_set = NULL; |
|||
|
|||
if (zend_hash_exists(&ce->function_table, CALL_HANDLER, sizeof(CALL_HANDLER))) { |
|||
oo_data.handle_function_call = ce->handle_function_call; |
|||
ce->handle_function_call = overload_call_method; |
|||
} else |
|||
oo_data.handle_function_call = NULL; |
|||
|
|||
zend_hash_index_update(&OOG(overloaded_classes), (long)ce, &oo_data, sizeof(oo_data), NULL); |
|||
|
|||
RETURN_TRUE; |
|||
} |
|||
/* }}} */ |
|||
|
|||
#endif /* HAVE_OVERLOAD */ |
|||
#endif /* ZEND_ENGINE_2 */ |
|||
|
|||
/* |
|||
* Local variables: |
|||
* tab-width: 4 |
|||
* c-basic-offset: 4 |
|||
* End: |
|||
* vim600: noet sw=4 ts=4 fdm=marker |
|||
* vim<600: noet sw=4 ts=4 |
|||
*/ |
|||
@ -1,108 +0,0 @@ |
|||
# Microsoft Developer Studio Project File - Name="overload" - Package Owner=<4> |
|||
# Microsoft Developer Studio Generated Build File, Format Version 6.00 |
|||
# ** DO NOT EDIT ** |
|||
|
|||
# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 |
|||
|
|||
CFG=overload - Win32 Debug_TS |
|||
!MESSAGE This is not a valid makefile. To build this project using NMAKE, |
|||
!MESSAGE use the Export Makefile command and run |
|||
!MESSAGE |
|||
!MESSAGE NMAKE /f "overload.mak". |
|||
!MESSAGE |
|||
!MESSAGE You can specify a configuration when running NMAKE |
|||
!MESSAGE by defining the macro CFG on the command line. For example: |
|||
!MESSAGE |
|||
!MESSAGE NMAKE /f "overload.mak" CFG="overload - Win32 Debug_TS" |
|||
!MESSAGE |
|||
!MESSAGE Possible choices for configuration are: |
|||
!MESSAGE |
|||
!MESSAGE "overload - Win32 Release_TS" (based on "Win32 (x86) Dynamic-Link Library") |
|||
!MESSAGE "overload - Win32 Debug_TS" (based on "Win32 (x86) Dynamic-Link Library") |
|||
!MESSAGE |
|||
|
|||
# Begin Project |
|||
# PROP AllowPerConfigDependencies 0 |
|||
# PROP Scc_ProjName "" |
|||
# PROP Scc_LocalPath "" |
|||
CPP=cl.exe |
|||
MTL=midl.exe |
|||
RSC=rc.exe |
|||
|
|||
!IF "$(CFG)" == "overload - Win32 Release_TS" |
|||
|
|||
# PROP BASE Use_MFC 0 |
|||
# PROP BASE Use_Debug_Libraries 0 |
|||
# PROP BASE Output_Dir "Release_TS" |
|||
# PROP BASE Intermediate_Dir "Release_TS" |
|||
# PROP BASE Ignore_Export_Lib 0 |
|||
# PROP BASE Target_Dir "" |
|||
# PROP Use_MFC 0 |
|||
# PROP Use_Debug_Libraries 0 |
|||
# PROP Output_Dir "Release_TS" |
|||
# PROP Intermediate_Dir "Release_TS" |
|||
# PROP Ignore_Export_Lib 0 |
|||
# PROP Target_Dir "" |
|||
# ADD BASE CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "overload_EXPORTS" /YX /FD /c |
|||
# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\.." /I "..\..\main" /I "..\..\Zend" /I "..\..\TSRM" /D ZEND_DEBUG=0 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "PHP_EXPORTS" /D "COMPILE_DL_OVERLOAD" /D ZTS=1 /D "ZEND_WIN32" /D "PHP_WIN32" /D HAVE_OVERLOAD=1 /YX /FD /c |
|||
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 |
|||
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 |
|||
# ADD BASE RSC /l 0x407 /d "NDEBUG" |
|||
# ADD RSC /l 0x407 /d "NDEBUG" |
|||
BSC32=bscmake.exe |
|||
# ADD BASE BSC32 /nologo |
|||
# ADD BSC32 /nologo |
|||
LINK32=link.exe |
|||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 |
|||
# ADD LINK32 php4ts.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"..\..\Release_TS/php_overload.dll" /libpath:"..\..\Release_TS" /libpath:"..\..\Release_TS_Inline" |
|||
|
|||
!ELSEIF "$(CFG)" == "overload - Win32 Debug_TS" |
|||
|
|||
# PROP BASE Use_MFC 0 |
|||
# PROP BASE Use_Debug_Libraries 1 |
|||
# PROP BASE Output_Dir "Debug_TS" |
|||
# PROP BASE Intermediate_Dir "Debug_TS" |
|||
# PROP BASE Target_Dir "" |
|||
# PROP Use_MFC 0 |
|||
# PROP Use_Debug_Libraries 1 |
|||
# PROP Output_Dir "Debug_TS" |
|||
# PROP Intermediate_Dir "Debug_TS" |
|||
# PROP Ignore_Export_Lib 0 |
|||
# PROP Target_Dir "" |
|||
# ADD BASE CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "overload_EXPORTS" /YX /FD /GZ /c |
|||
# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\.." /I "..\..\main" /I "..\..\Zend" /I "..\..\TSRM" /D ZEND_DEBUG=1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "PHP_EXPORTS" /D "COMPILE_DL_OVERLOAD" /D ZTS=1 /D "ZEND_WIN32" /D "PHP_WIN32" /D HAVE_OVERLOAD=1 /YX /FD /GZ /c |
|||
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 |
|||
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 |
|||
# ADD BASE RSC /l 0x407 /d "_DEBUG" |
|||
# ADD RSC /l 0x407 /d "_DEBUG" |
|||
BSC32=bscmake.exe |
|||
# ADD BASE BSC32 /nologo |
|||
# ADD BSC32 /nologo |
|||
LINK32=link.exe |
|||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept |
|||
# ADD LINK32 php4ts_debug.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /out:"..\..\Debug_TS/php_overload.dll" /pdbtype:sept /libpath:"..\..\Debug_TS" |
|||
|
|||
!ENDIF |
|||
|
|||
# Begin Target |
|||
|
|||
# Name "overload - Win32 Release_TS" |
|||
# Name "overload - Win32 Debug_TS" |
|||
# Begin Group "Source Files" |
|||
|
|||
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" |
|||
# Begin Source File |
|||
|
|||
SOURCE=.\overload.c |
|||
# End Source File |
|||
# End Group |
|||
# Begin Group "Header Files" |
|||
|
|||
# PROP Default_Filter "h;hpp;hxx;hm;inl" |
|||
# Begin Source File |
|||
|
|||
SOURCE=.\php_overload.h |
|||
# End Source File |
|||
# End Group |
|||
# End Target |
|||
# End Project |
|||
@ -1,67 +0,0 @@ |
|||
/* |
|||
+----------------------------------------------------------------------+ |
|||
| PHP Version 4 | |
|||
+----------------------------------------------------------------------+ |
|||
| Copyright (c) 1997-2003 The PHP Group | |
|||
+----------------------------------------------------------------------+ |
|||
| This source file is subject to version 2.02 of the PHP license, | |
|||
| that is bundled with this package in the file LICENSE, and is | |
|||
| available at through the world-wide-web at | |
|||
| http://www.php.net/license/2_02.txt. | |
|||
| If you did not receive a copy of the PHP license and are unable to | |
|||
| obtain it through the world-wide-web, please send a note to | |
|||
| license@php.net so we can mail you a copy immediately. | |
|||
+----------------------------------------------------------------------+ |
|||
| Author: Andrei Zmievski <andrei@php.net> | |
|||
+----------------------------------------------------------------------+ |
|||
*/ |
|||
|
|||
#ifndef PHP_OVERLOAD_H |
|||
#define PHP_OVERLOAD_H |
|||
|
|||
#ifndef ZEND_ENGINE_2 |
|||
#if HAVE_OVERLOAD |
|||
|
|||
extern zend_module_entry overload_module_entry; |
|||
#define phpext_overload_ptr &overload_module_entry |
|||
|
|||
#ifdef PHP_WIN32 |
|||
#define PHP_OVERLOAD_API __declspec(dllexport) |
|||
#else |
|||
#define PHP_OVERLOAD_API |
|||
#endif |
|||
|
|||
#ifdef ZTS |
|||
#include "TSRM.h" |
|||
#endif |
|||
|
|||
PHP_MINIT_FUNCTION(overload); |
|||
PHP_MSHUTDOWN_FUNCTION(overload); |
|||
PHP_RSHUTDOWN_FUNCTION(overload); |
|||
PHP_MINFO_FUNCTION(overload); |
|||
|
|||
PHP_FUNCTION(overload); |
|||
|
|||
ZEND_BEGIN_MODULE_GLOBALS(overload) |
|||
HashTable overloaded_classes; |
|||
ZEND_END_MODULE_GLOBALS(overload) |
|||
|
|||
#ifdef ZTS |
|||
#define OOG(v) TSRMG(overload_globals_id, zend_overload_globals *, v) |
|||
#else |
|||
#define OOG(v) (overload_globals.v) |
|||
#endif |
|||
|
|||
#endif /* HAVE_OVERLOAD */ |
|||
#endif /* ZEND_ENGINE_2 */ |
|||
|
|||
#endif /* PHP_OVERLOAD_H */ |
|||
|
|||
|
|||
/* |
|||
* Local variables: |
|||
* tab-width: 4 |
|||
* c-basic-offset: 4 |
|||
* indent-tabs-mode: t |
|||
* End: |
|||
*/ |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue