首页 > 代码库 > php 对象调用方法

php 对象调用方法

static union _zend_function *zend_std_get_method(zval **object_ptr, char *method_name, int method_len, const zend_literal *key TSRMLS_DC) /* {{{ */{    zend_function *fbc;    zval *object = *object_ptr;    zend_object *zobj = Z_OBJ_P(object);    ulong hash_value;    char *lc_method_name;    ALLOCA_FLAG(use_heap)    if (EXPECTED(key != NULL)) {        lc_method_name = Z_STRVAL(key->constant);        hash_value = key->hash_value;    } else {        lc_method_name = do_alloca(method_len+1, use_heap);        /* Create a zend_copy_str_tolower(dest, src, src_length); */        zend_str_tolower_copy(lc_method_name, method_name, method_len);        hash_value = zend_hash_func(lc_method_name, method_len+1);    }    if (UNEXPECTED(zend_hash_quick_find(&zobj->ce->function_table, lc_method_name, method_len+1, hash_value, (void **)&fbc) == FAILURE)) {        if (UNEXPECTED(!key)) {            free_alloca(lc_method_name, use_heap);        }        if (zobj->ce->__call) {//如果找不到,调用_call()方法            return zend_get_user_call_function(zobj->ce, method_name, method_len);        } else {            return NULL;        }    }    /* Check access level */    if (fbc->op_array.fn_flags & ZEND_ACC_PRIVATE) {        zend_function *updated_fbc;        /* Ensure that if we‘re calling a private function, we‘re allowed to do so.         * If we‘re not and __call() handler exists, invoke it, otherwise error out.         */        updated_fbc = zend_check_private_int(fbc, Z_OBJ_HANDLER_P(object, get_class_entry)(object TSRMLS_CC), lc_method_name, method_len, hash_value TSRMLS_CC);        if (EXPECTED(updated_fbc != NULL)) {            fbc = updated_fbc;        } else {            if (zobj->ce->__call) {                fbc = zend_get_user_call_function(zobj->ce, method_name, method_len);            } else {                zend_error_noreturn(E_ERROR, "Call to %s method %s::%s() from context ‘%s‘", zend_visibility_string(fbc->common.fn_flags), ZEND_FN_SCOPE_NAME(fbc), method_name, EG(scope) ? EG(scope)->name : "");            }        }    } else {        /* Ensure that we haven‘t overridden a private function and end up calling         * the overriding public function...         */        if (EG(scope) &&            is_derived_class(fbc->common.scope, EG(scope)) &&            fbc->op_array.fn_flags & ZEND_ACC_CHANGED) {            zend_function *priv_fbc;            if (zend_hash_quick_find(&EG(scope)->function_table, lc_method_name, method_len+1, hash_value, (void **) &priv_fbc)==SUCCESS                && priv_fbc->common.fn_flags & ZEND_ACC_PRIVATE                && priv_fbc->common.scope == EG(scope)) {                fbc = priv_fbc;            }        }        if ((fbc->common.fn_flags & ZEND_ACC_PROTECTED)) {            /* Ensure that if we‘re calling a protected function, we‘re allowed to do so.             * If we‘re not and __call() handler exists, invoke it, otherwise error out.             */            if (UNEXPECTED(!zend_check_protected(zend_get_function_root_class(fbc), EG(scope)))) {                if (zobj->ce->__call) {                    fbc = zend_get_user_call_function(zobj->ce, method_name, method_len);                } else {                    zend_error_noreturn(E_ERROR, "Call to %s method %s::%s() from context ‘%s‘", zend_visibility_string(fbc->common.fn_flags), ZEND_FN_SCOPE_NAME(fbc), method_name, EG(scope) ? EG(scope)->name : "");                }            }        }    }    if (UNEXPECTED(!key)) {        free_alloca(lc_method_name, use_heap);    }    return fbc;}

 

static inline union _zend_function *zend_get_user_call_function(zend_class_entry *ce, const char *method_name, int method_len) /* {{{ */{    zend_internal_function *call_user_call = emalloc(sizeof(zend_internal_function));    call_user_call->type = ZEND_INTERNAL_FUNCTION;    call_user_call->module = (ce->type == ZEND_INTERNAL_CLASS) ? ce->info.internal.module : NULL;    call_user_call->handler = zend_std_call_user_call;    call_user_call->arg_info = NULL;    call_user_call->num_args = 0;    call_user_call->scope = ce;    call_user_call->fn_flags = ZEND_ACC_CALL_VIA_HANDLER;    call_user_call->function_name = estrndup(method_name, method_len);    return (union _zend_function *)call_user_call;}

 

 

ZEND_API void zend_std_call_user_call(INTERNAL_FUNCTION_PARAMETERS) /* {{{ */{    zend_internal_function *func = (zend_internal_function *)EG(current_execute_data)->function_state.function;    zval *method_name_ptr, *method_args_ptr;    zval *method_result_ptr = NULL;    zend_class_entry *ce = Z_OBJCE_P(this_ptr);    ALLOC_ZVAL(method_args_ptr);    INIT_PZVAL(method_args_ptr);    array_init_size(method_args_ptr, ZEND_NUM_ARGS());    if (UNEXPECTED(zend_copy_parameters_array(ZEND_NUM_ARGS(), method_args_ptr TSRMLS_CC) == FAILURE)) {        zval_dtor(method_args_ptr);        zend_error_noreturn(E_ERROR, "Cannot get arguments for __call");        RETURN_FALSE;    }    ALLOC_ZVAL(method_name_ptr);    INIT_PZVAL(method_name_ptr);    ZVAL_STRING(method_name_ptr, func->function_name, 0); /* no dup - it‘s a copy */    /* __call handler is called with two arguments:       method name       array of method parameters    */    zend_call_method_with_2_params(&this_ptr, ce, &ce->__call, ZEND_CALL_FUNC_NAME, &method_result_ptr, method_name_ptr, method_args_ptr);    if (method_result_ptr) {        if (Z_ISREF_P(method_result_ptr) || Z_REFCOUNT_P(method_result_ptr) > 1) {            RETVAL_ZVAL(method_result_ptr, 1, 1);        } else {            RETVAL_ZVAL(method_result_ptr, 0, 1);        }    }    /* now destruct all auxiliaries */    zval_ptr_dtor(&method_args_ptr);    zval_ptr_dtor(&method_name_ptr);    /* destruct the function also, then - we have allocated it in get_method */    efree(func);}

 

 

/* Ensures that we‘re allowed to call a private method. * Returns the function address that should be called, or NULL * if no such function exists. */static inline zend_function *zend_check_private_int(zend_function *fbc, zend_class_entry *ce, char *function_name_strval, int function_name_strlen, ulong hash_value TSRMLS_DC) /* {{{ */{    if (!ce) {        return 0;    }    /* We may call a private function if:     * 1.  The class of our object is the same as the scope, and the private     *     function (EX(fbc)) has the same scope.     * 2.  One of our parent classes are the same as the scope, and it contains     *     a private function with the same name that has the same scope.     */    if (fbc->common.scope == ce && EG(scope) == ce) {        /* rule #1 checks out ok, allow the function call */        return fbc;    }    /* Check rule #2 */    ce = ce->parent;    while (ce) {        if (ce == EG(scope)) {            if (zend_hash_quick_find(&ce->function_table, function_name_strval, function_name_strlen+1, hash_value, (void **) &fbc)==SUCCESS                && fbc->op_array.fn_flags & ZEND_ACC_PRIVATE                && fbc->common.scope == EG(scope)) {                return fbc;            }            break;        }        ce = ce->parent;    }    return NULL;}

 

ZEND_API void zend_hash_merge_ex(HashTable *target, HashTable *source, copy_ctor_func_t pCopyConstructor, uint size, merge_checker_func_t pMergeSource, void *pParam){    Bucket *p;    void *t;    IS_CONSISTENT(source);    IS_CONSISTENT(target);    p = source->pListHead;    while (p) {        if (zend_hash_replace_checker_wrapper(target, p->pData, p, pParam, pMergeSource)) {            if (zend_hash_quick_update(target, p->arKey, p->nKeyLength, p->h, p->pData, size, &t)==SUCCESS && pCopyConstructor) {                pCopyConstructor(t);            }        }        p = p->pListNext;    }    target->pInternalPointer = target->pListHead;}

 

 

static zend_bool zend_hash_replace_checker_wrapper(HashTable *target, void *source_data, Bucket *p, void *pParam, merge_checker_func_t merge_checker_func){    zend_hash_key hash_key;    hash_key.arKey = p->arKey;    hash_key.nKeyLength = p->nKeyLength;    hash_key.h = p->h;    return merge_checker_func(target, source_data, &hash_key, pParam);}static zend_bool do_inherit_property_access_check(HashTable *target_ht, zend_property_info *parent_info, const zend_hash_key *hash_key, zend_class_entry *ce) /* {{{ */{    zend_property_info *child_info;    zend_class_entry *parent_ce = ce->parent;    if (parent_info->flags & (ZEND_ACC_PRIVATE|ZEND_ACC_SHADOW)) { //如果父类中的属性是private的,则返回0,不拷贝        if (zend_hash_quick_find(&ce->properties_info, hash_key->arKey, hash_key->nKeyLength, hash_key->h, (void **) &child_info)==SUCCESS) {            child_info->flags |= ZEND_ACC_CHANGED;        } else {            zend_hash_quick_update(&ce->properties_info, hash_key->arKey, hash_key->nKeyLength, hash_key->h, parent_info, sizeof(zend_property_info), (void **) &child_info);            if(ce->type & ZEND_INTERNAL_CLASS) {                zend_duplicate_property_info_internal(child_info);            } else {                zend_duplicate_property_info(child_info);            }            child_info->flags &= ~ZEND_ACC_PRIVATE; /* it‘s not private anymore */            child_info->flags |= ZEND_ACC_SHADOW; /* but it‘s a shadow of private */        }        return 0; /* don‘t copy access information to child */    }    if (zend_hash_quick_find(&ce->properties_info, hash_key->arKey, hash_key->nKeyLength, hash_key->h, (void **) &child_info)==SUCCESS) {        if ((parent_info->flags & ZEND_ACC_STATIC) != (child_info->flags & ZEND_ACC_STATIC)) {            zend_error(E_COMPILE_ERROR, "Cannot redeclare %s%s::$%s as %s%s::$%s",                (parent_info->flags & ZEND_ACC_STATIC) ? "static " : "non static ", parent_ce->name, hash_key->arKey,                (child_info->flags & ZEND_ACC_STATIC) ? "static " : "non static ", ce->name, hash_key->arKey);                        }        if(parent_info->flags & ZEND_ACC_CHANGED) {            child_info->flags |= ZEND_ACC_CHANGED;        }        if ((child_info->flags & ZEND_ACC_PPP_MASK) > (parent_info->flags & ZEND_ACC_PPP_MASK)) {            zend_error(E_COMPILE_ERROR, "Access level to %s::$%s must be %s (as in class %s)%s", ce->name, hash_key->arKey, zend_visibility_string(parent_info->flags), parent_ce->name, (parent_info->flags&ZEND_ACC_PUBLIC) ? "" : " or weaker");        } else if ((child_info->flags & ZEND_ACC_STATIC) == 0) {            zval_ptr_dtor(&(ce->default_properties_table[parent_info->offset]));            ce->default_properties_table[parent_info->offset] = ce->default_properties_table[child_info->offset];            ce->default_properties_table[child_info->offset] = NULL;            child_info->offset = parent_info->offset;        }        return 0;    /* Don‘t copy from parent */    } else { 
//子类中没有找到父类中的属性
return 1; /* Copy from parent */ }}

 

 

static void do_inheritance_check_on_method(zend_function *child, zend_function *parent TSRMLS_DC) /* {{{ */{    zend_uint child_flags;    zend_uint parent_flags = parent->common.fn_flags;    if ((parent->common.scope->ce_flags & ZEND_ACC_INTERFACE) == 0        && parent->common.fn_flags & ZEND_ACC_ABSTRACT        && parent->common.scope != (child->common.prototype ? child->common.prototype->common.scope : child->common.scope)        && child->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_IMPLEMENTED_ABSTRACT)) {        zend_error(E_COMPILE_ERROR, "Can‘t inherit abstract function %s::%s() (previously declared abstract in %s)",             parent->common.scope->name,            child->common.function_name,            child->common.prototype ? child->common.prototype->common.scope->name : child->common.scope->name);    }    if (parent_flags & ZEND_ACC_FINAL) {        zend_error(E_COMPILE_ERROR, "Cannot override final method %s::%s()", ZEND_FN_SCOPE_NAME(parent), child->common.function_name);    }    child_flags    = child->common.fn_flags;    /* You cannot change from static to non static and vice versa.     */    if ((child_flags & ZEND_ACC_STATIC) != (parent_flags & ZEND_ACC_STATIC)) {        if (child->common.fn_flags & ZEND_ACC_STATIC) {            zend_error(E_COMPILE_ERROR, "Cannot make non static method %s::%s() static in class %s", ZEND_FN_SCOPE_NAME(parent), child->common.function_name, ZEND_FN_SCOPE_NAME(child));        } else {            zend_error(E_COMPILE_ERROR, "Cannot make static method %s::%s() non static in class %s", ZEND_FN_SCOPE_NAME(parent), child->common.function_name, ZEND_FN_SCOPE_NAME(child));        }    }    /* Disallow making an inherited method abstract. */    if ((child_flags & ZEND_ACC_ABSTRACT) && !(parent_flags & ZEND_ACC_ABSTRACT)) {        zend_error(E_COMPILE_ERROR, "Cannot make non abstract method %s::%s() abstract in class %s", ZEND_FN_SCOPE_NAME(parent), child->common.function_name, ZEND_FN_SCOPE_NAME(child));    }    if (parent_flags & ZEND_ACC_CHANGED) {        child->common.fn_flags |= ZEND_ACC_CHANGED;    } else {        /* Prevent derived classes from restricting access that was available in parent classes         */        if ((child_flags & ZEND_ACC_PPP_MASK) > (parent_flags & ZEND_ACC_PPP_MASK)) {            zend_error(E_COMPILE_ERROR, "Access level to %s::%s() must be %s (as in class %s)%s", ZEND_FN_SCOPE_NAME(child), child->common.function_name, zend_visibility_string(parent_flags), ZEND_FN_SCOPE_NAME(parent), (parent_flags&ZEND_ACC_PUBLIC) ? "" : " or weaker");        } else if (((child_flags & ZEND_ACC_PPP_MASK) < (parent_flags & ZEND_ACC_PPP_MASK))            && ((parent_flags & ZEND_ACC_PPP_MASK) & ZEND_ACC_PRIVATE)) {            child->common.fn_flags |= ZEND_ACC_CHANGED;        }    }    if (parent_flags & ZEND_ACC_PRIVATE) {        child->common.prototype = NULL;            } else if (parent_flags & ZEND_ACC_ABSTRACT) {        child->common.fn_flags |= ZEND_ACC_IMPLEMENTED_ABSTRACT;        child->common.prototype = parent;    } else if (!(parent->common.fn_flags & ZEND_ACC_CTOR) || (parent->common.prototype && (parent->common.prototype->common.scope->ce_flags & ZEND_ACC_INTERFACE))) {        /* ctors only have a prototype if it comes from an interface */        child->common.prototype = parent->common.prototype ? parent->common.prototype : parent;    }    if (child->common.prototype && (child->common.prototype->common.fn_flags & ZEND_ACC_ABSTRACT)) {        if (!zend_do_perform_implementation_check(child, child->common.prototype TSRMLS_CC)) {            zend_error(E_COMPILE_ERROR, "Declaration of %s::%s() must be compatible with %s", ZEND_FN_SCOPE_NAME(child), child->common.function_name, zend_get_function_declaration(child->common.prototype? child->common.prototype : parent TSRMLS_CC));         }    } else if (EG(error_reporting) & E_STRICT || EG(user_error_handler)) { /* Check E_STRICT (or custom error handler) before the check so that we save some time */        if (!zend_do_perform_implementation_check(child, parent TSRMLS_CC)) {            char *method_prototype = zend_get_function_declaration(child->common.prototype? child->common.prototype : parent TSRMLS_CC);            zend_error(E_STRICT, "Declaration of %s::%s() should be compatible with %s", ZEND_FN_SCOPE_NAME(child), child->common.function_name, method_prototype);             efree(method_prototype);        }    }}

 

 

 

php 对象调用方法