]> granicus.if.org Git - php/commitdiff
- Simplify and synch is_callable_ex() with actual execution code
authorMarcus Boerger <helly@php.net>
Fri, 16 Dec 2005 22:15:41 +0000 (22:15 +0000)
committerMarcus Boerger <helly@php.net>
Fri, 16 Dec 2005 22:15:41 +0000 (22:15 +0000)
  . Allow array($this, 'parent::method') for function 'pointers'
  . Spit out E_STRICT in case of erroneous use of function 'pointers'

Zend/zend_API.c
Zend/zend_API.h
Zend/zend_execute_API.c

index bae16c5492e4a3bcc2da4d73879581dc30a6b572..81921ff57448aaa044ed1b3f55930eac23144479 100644 (file)
@@ -1974,15 +1974,94 @@ ZEND_API int zend_disable_class(char *class_name, uint class_name_length TSRMLS_
        return 1;
 }
 
-ZEND_API zend_bool zend_is_callable_ex(zval *callable, uint check_flags, char **callable_name, int *callable_name_len, zend_class_entry **ce_ptr, zend_function **fptr_ptr, zval ***zobj_ptr_ptr TSRMLS_DC)
+static int zend_is_callable_check_func(int check_flags, zval **zobj_ptr, zend_class_entry *ce_org, zval *callable, zend_class_entry **ce_ptr, zend_function **fptr_ptr TSRMLS_DC)
 {
+       int retval;
        char *lcname, *lmname, *colon;
+       int clen, mlen;
+       zend_function *fptr;
+       zend_class_entry **pce;
+       HashTable *ftable;
+       
+       *ce_ptr = NULL;
+       *fptr_ptr = NULL;
+
+       if ((colon = strstr(Z_STRVAL_P(callable), "::")) != NULL) {
+               clen = colon - Z_STRVAL_P(callable);
+               mlen = Z_STRLEN_P(callable) - clen - 2;
+               if (zend_lookup_class(Z_STRVAL_P(callable), clen, &pce TSRMLS_CC) == SUCCESS) {
+                       *ce_ptr = *pce;
+               } else {
+                       lcname = zend_str_tolower_dup(Z_STRVAL_P(callable), clen);
+                       /* caution: lcname is not '\0' terminated */
+                       if (clen == sizeof("self") - 1 && memcmp(lcname, "self", sizeof("self") - 1) == 0) {
+                               *ce_ptr = EG(scope);
+                       } else if (clen == sizeof("parent") - 1 && memcmp(lcname, "parent", sizeof("parent") - 1) == 0 && EG(active_op_array)->scope) {
+                               *ce_ptr = EG(scope) ? EG(scope)->parent : NULL;
+                       }
+                       efree(lcname);
+               }
+               if (!*ce_ptr) {
+                       return 0;
+               }
+               ftable = &(*ce_ptr)->function_table;
+               if (ce_org && !instanceof_function(ce_org, *ce_ptr TSRMLS_CC)) {
+                       return 0;
+               }
+               lmname = zend_str_tolower_dup(Z_STRVAL_P(callable) + clen + 2, mlen);
+       } else {
+               mlen = Z_STRLEN_P(callable);
+               lmname = zend_str_tolower_dup(Z_STRVAL_P(callable), mlen);
+               if (ce_org) {
+                       ftable = &ce_org->function_table;
+                       *ce_ptr = ce_org;
+               } else {
+                       ftable = EG(function_table);
+               }
+       }
+
+       retval = zend_hash_find(ftable, lmname, mlen+1, (void**)&fptr) == SUCCESS ? 1 : 0;
+
+       if (!retval) {
+               if (zobj_ptr && *ce_ptr && (*ce_ptr)->__call != 0) {
+                       retval = (*ce_ptr)->__call != NULL;
+                       *fptr_ptr = (*ce_ptr)->__call;
+               }
+       } else {
+               *fptr_ptr = fptr;
+               if (*ce_ptr) {
+                       if (!zobj_ptr && !(fptr->common.fn_flags & ZEND_ACC_STATIC)) {
+                               if ((check_flags & IS_CALLABLE_CHECK_IS_STATIC) != 0) {
+                                       retval = 0;
+                               } else {
+                                       zend_error(E_STRICT, "Non-static method %s::%s() cannot be called statically", (*ce_ptr)->name, fptr->common.function_name);
+                               }
+                       }
+                       if (retval && (check_flags & IS_CALLABLE_CHECK_NO_ACCESS) == 0) {
+                               if (fptr->op_array.fn_flags & ZEND_ACC_PRIVATE) {
+                                       if (!zend_check_private(fptr, zobj_ptr ? Z_OBJCE_PP(zobj_ptr) : EG(scope), lmname, mlen TSRMLS_CC)) {
+                                               retval = 0;
+                                       }
+                               } else if ((fptr->common.fn_flags & ZEND_ACC_PROTECTED)) {
+                                       if (!zend_check_protected(fptr->common.scope, EG(scope))) {
+                                               retval = 0;
+                                       }
+                               }
+                       }
+               }
+       }
+       efree(lmname);
+       return retval;
+}
+
+ZEND_API zend_bool zend_is_callable_ex(zval *callable, uint check_flags, char **callable_name, int *callable_name_len, zend_class_entry **ce_ptr, zend_function **fptr_ptr, zval ***zobj_ptr_ptr TSRMLS_DC)
+{
+       char *lcname;
        zend_bool retval = 0; 
-       int callable_name_len_local, clen, mlen;
+       int callable_name_len_local;
        zend_class_entry *ce_local, **pce;
        zend_function *fptr_local;
        zval **zobj_ptr_local;
-       HashTable *ftable;
 
        if (callable_name_len == NULL) {
                callable_name_len = &callable_name_len_local;
@@ -2010,33 +2089,7 @@ ZEND_API zend_bool zend_is_callable_ex(zval *callable, uint check_flags, char **
                                return 1;
                        }
                        
-                       if ((colon = strstr(Z_STRVAL_P(callable), "::")) != NULL) {
-                               clen = colon - Z_STRVAL_P(callable);
-                               mlen = Z_STRLEN_P(callable) - clen - 2;
-                               lcname = estrndup(Z_STRVAL_P(callable), clen);
-                               lcname[clen] = '\0';
-                               lmname = zend_str_tolower_dup(Z_STRVAL_P(callable) + clen + 2, mlen);
-                               if (zend_lookup_class(lcname, clen, &pce TSRMLS_CC) == FAILURE) {
-                                       efree(lcname);
-                                       efree(lmname);
-                                       return 0;
-                               }
-                               efree(lcname);
-                               *ce_ptr = *pce;
-                               ftable = &(*ce_ptr)->function_table;
-                       } else {
-                               mlen = Z_STRLEN_P(callable);
-                               lmname = zend_str_tolower_dup(Z_STRVAL_P(callable), mlen);
-                               ftable = EG(function_table);
-                       }
-
-                       if (zend_hash_find(ftable, lmname, mlen+1, (void**)fptr_ptr) == SUCCESS) {
-                               retval = 1;
-                       }
-                       if (*ce_ptr && *fptr_ptr && !((*fptr_ptr)->common.fn_flags & ZEND_ACC_STATIC)) {
-                               retval = 0;
-                       }
-                       efree(lmname);
+                       retval = zend_is_callable_check_func(check_flags|IS_CALLABLE_CHECK_IS_STATIC, NULL, NULL, callable, ce_ptr, fptr_ptr TSRMLS_CC);
                        break;
 
                case IS_ARRAY:
@@ -2065,7 +2118,6 @@ ZEND_API zend_bool zend_is_callable_ex(zval *callable, uint check_flags, char **
                                                }
 
                                                if (check_flags & IS_CALLABLE_CHECK_SYNTAX_ONLY) {
-                                                       *ce_ptr = ce;
                                                        return 1;
                                                }
 
@@ -2080,6 +2132,12 @@ ZEND_API zend_bool zend_is_callable_ex(zval *callable, uint check_flags, char **
                                                        }
                                                        efree(lcname);
                                                }
+                                               if (EG(This)) {
+                                                       if (instanceof_function(Z_OBJCE_P(EG(This)), ce TSRMLS_CC)) {
+                                                               *zobj_ptr_ptr = &EG(This);
+                                                               zend_error(E_STRICT, "Non-static method %s::%s() canot be called statically, assuming $this from compatible context %s", ce->name, Z_STRVAL_PP(method), Z_OBJCE_P(EG(This))->name);
+                                                       }
+                                               }
                                        } else {
                                                ce = Z_OBJCE_PP(obj); /* TBFixed: what if it's overloaded? */
                                                
@@ -2104,38 +2162,12 @@ ZEND_API zend_bool zend_is_callable_ex(zval *callable, uint check_flags, char **
                                        }
 
                                        if (ce) {
-                                               zend_function *fbc;
-
-                                               lcname = zend_str_tolower_dup(Z_STRVAL_PP(method), Z_STRLEN_PP(method));
-                                               if (zend_hash_find(&ce->function_table, lcname, Z_STRLEN_PP(method)+1, (void **)&fbc) == SUCCESS) {
-                                                       retval = 1;
-                                                       if ((check_flags & IS_CALLABLE_CHECK_NO_ACCESS) == 0) {
-                                                               if (fbc->op_array.fn_flags & ZEND_ACC_PRIVATE) {
-                                                                       if (!zend_check_private(fbc, (Z_TYPE_PP(obj) == IS_STRING)?EG(scope):(*obj)->value.obj.handlers->get_class_entry(*obj TSRMLS_CC), lcname, Z_STRLEN_PP(method) TSRMLS_CC)) {
-                                                                               retval = 0;
-                                                                       }
-                                                               } else if ((fbc->common.fn_flags & ZEND_ACC_PROTECTED)) {
-                                                                       if (!zend_check_protected(fbc->common.scope, EG(scope))) {
-                                                                               retval = 0;
-                                                                       }
-                                                               }
-                                                       }
-                                                       *fptr_ptr = fbc;
-                                               }
-                                               /* check for __call too */
-                                               if (retval == 0 && *zobj_ptr_ptr && ce->__call != 0) {
-                                                       retval = 1;
-                                                       *fptr_ptr = ce->__call;
-                                               }
-                                               efree(lcname);
+                                               retval = zend_is_callable_check_func(check_flags, *zobj_ptr_ptr, ce, *method, ce_ptr, fptr_ptr TSRMLS_CC);
                                        }
                                } else if (callable_name) {
                                        *callable_name = estrndup("Array", sizeof("Array")-1);
                                        *callable_name_len = sizeof("Array") - 1;
                                }
-                               if ((check_flags & IS_CALLABLE_CHECK_IS_STATIC) != 0 && !*zobj_ptr_ptr && (!*fptr_ptr || !((*fptr_ptr)->common.fn_flags & ZEND_ACC_STATIC))) {
-                                       retval = 0;
-                               }
                                *ce_ptr = ce;
                        }
                        break;
index d30d7f74996830d5565ecd7ce1b70b49e8797d20..61f4d880d03be79625ca29143e8d2f1db1b471c8 100644 (file)
@@ -204,6 +204,8 @@ ZEND_API void zend_wrong_param_count(TSRMLS_D);
 #define IS_CALLABLE_CHECK_NO_ACCESS   (1<<1)
 #define IS_CALLABLE_CHECK_IS_STATIC   (1<<2)
 
+#define IS_CALLABLE_STRICT  (IS_CALLABLE_CHECK_IS_STATIC)
+
 ZEND_API zend_bool zend_is_callable_ex(zval *callable, uint check_flags, char **callable_name, int *callable_name_len, zend_class_entry **ce_ptr, zend_function **fptr_ptr, zval ***zobj_ptr_ptr TSRMLS_DC);
 ZEND_API zend_bool zend_is_callable(zval *callable, uint check_flags, char **callable_name);
 ZEND_API zend_bool zend_make_callable(zval *callable, char **callable_name TSRMLS_DC);
index 865f56699434744cda4d165ddb0ed30bc887ac28..4618d7b85e8dbbd691b59d360e7fe984324ab5ce 100644 (file)
@@ -587,6 +587,8 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS
        zval *method_name;
        zval *params_array;
        int call_via_handler = 0;
+       char *fname, *colon;
+       int fname_len;
 
        if (EG(exception)) {
                return FAILURE; /* we would result in an instable executor otherwise */
@@ -706,30 +708,62 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS
                        return FAILURE;
                }
 
+               fname = Z_STRVAL_P(fci->function_name);
+               fname_len = Z_STRLEN_P(fci->function_name);
+               if (calling_scope && (colon = strstr(fname, "::")) != NULL) {
+                       int clen = colon - fname;
+                       int mlen = fname_len - clen - 2;
+                       zend_class_entry **pce, *ce_child;
+                       if (zend_lookup_class(fname, clen, &pce TSRMLS_CC) == SUCCESS) {
+                               ce_child = *pce;
+                       } else {
+                               char *lcname = zend_str_tolower_dup(fname, clen);
+                               /* caution: lcname is not '\0' terminated */
+                               if (clen == sizeof("self") - 1 && memcmp(lcname, "self", sizeof("self") - 1) == 0) {
+                                       ce_child = EG(active_op_array) ? EG(active_op_array)->scope : NULL;
+                               } else if (clen == sizeof("parent") - 1 && memcmp(lcname, "parent", sizeof("parent") - 1) == 0 && EG(active_op_array)->scope) {
+                                       ce_child = EG(active_op_array) && EG(active_op_array)->scope ? EG(scope)->parent : NULL;
+                               }
+                               efree(lcname);
+                       }
+                       if (!ce_child) {
+                               zend_error(E_ERROR, "Cannot call method %s() or method does not exist", fname);
+                               return FAILURE;
+                       }
+                       if (!instanceof_function(calling_scope, ce_child TSRMLS_CC)) {
+                               zend_error(E_ERROR, "Cannot call method %s() of class %s which is not a derived from %s", fname, ce_child->name, calling_scope->name);
+                               return 0;
+                       }
+                       fci->function_table = &ce_child->function_table;
+                       calling_scope = ce_child;
+                       fname = fname + clen + 2;
+                       fname_len = mlen;
+               }
+
                if (fci->object_pp) {
                        if (Z_OBJ_HT_PP(fci->object_pp)->get_method == NULL) {
                                zend_error(E_ERROR, "Object does not support method calls");
                        }
                        EX(function_state).function = 
-                         Z_OBJ_HT_PP(fci->object_pp)->get_method(fci->object_pp, Z_STRVAL_P(fci->function_name), Z_STRLEN_P(fci->function_name) TSRMLS_CC);
+                         Z_OBJ_HT_PP(fci->object_pp)->get_method(fci->object_pp, fname, fname_len TSRMLS_CC);
                        if (EX(function_state).function && calling_scope != EX(function_state).function->common.scope) {
-                               char *function_name_lc = zend_str_tolower_dup(Z_STRVAL_P(fci->function_name), Z_STRLEN_P(fci->function_name));
-                               if (zend_hash_find(&calling_scope->function_table, function_name_lc, fci->function_name->value.str.len+1, (void **) &EX(function_state).function)==FAILURE) {
+                               char *function_name_lc = zend_str_tolower_dup(fname, fname_len);
+                               if (zend_hash_find(&calling_scope->function_table, function_name_lc, fname_len+1, (void **) &EX(function_state).function)==FAILURE) {
                                        efree(function_name_lc);
-                                       zend_error(E_ERROR, "Cannot call method %s::%s() or method does not exist", calling_scope->name, Z_STRVAL_P(fci->function_name));
+                                       zend_error(E_ERROR, "Cannot call method %s::%s() or method does not exist", calling_scope->name, fname);
                                }
                                efree(function_name_lc);
                        }
                } else if (calling_scope) {
-                       char *function_name_lc = zend_str_tolower_dup(Z_STRVAL_P(fci->function_name), Z_STRLEN_P(fci->function_name));
+                       char *function_name_lc = zend_str_tolower_dup(fname, fname_len);
 
                        EX(function_state).function = 
-                               zend_std_get_static_method(calling_scope, function_name_lc, Z_STRLEN_P(fci->function_name) TSRMLS_CC);
+                               zend_std_get_static_method(calling_scope, function_name_lc, fname_len TSRMLS_CC);
                        efree(function_name_lc);
                } else {
-                       char *function_name_lc = zend_str_tolower_dup(Z_STRVAL_P(fci->function_name), Z_STRLEN_P(fci->function_name));
+                       char *function_name_lc = zend_str_tolower_dup(fname, fname_len);
 
-                       if (zend_hash_find(fci->function_table, function_name_lc, fci->function_name->value.str.len+1, (void **) &EX(function_state).function)==FAILURE) {
+                       if (zend_hash_find(fci->function_table, function_name_lc, fname_len+1, (void **) &EX(function_state).function)==FAILURE) {
                          EX(function_state).function = NULL;
                        }
                        efree(function_name_lc);