zoukankan      html  css  js  c++  java
  • 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);
            }
        }
    }

     

  • 相关阅读:
    Potato工作流管理系统 组织模型用例描述
    6/27 项目编码开始:一个简单的员工管理程序
    6/16 6/17加班2天
    重新过一遍ASP.NET 2.0(C#)(8) DataSourceControl(数据源控件)
    可行性分析报告结构
    6/27 一个简单的员工管理程序:添加微软成员资格数据表
    在asp.net 2.0中使用母版页和工厂方法模式
    工作流功能特性
    6/21 系统分析阶段汇报
    什么是工作流
  • 原文地址:https://www.cnblogs.com/taek/p/4133080.html
Copyright © 2011-2022 走看看