原创:PHP内核研究之类的访问控制
作者 斯人 | 发布于 2012 年 3 月 14 日
PHP PHP内核

今天本来说要去成龙电影院去看碟中谍4的..票买了到现在还没看.
明天就到期了..等了半天公交车.没等到..最后还是没看成
没办法就直接回家了啊..哎
今天就继续PHP内核 类的研究吧.
在PHP里面,类的访问控制有三种修饰符
public:可以被任意访问
private:只有本类能访问
protected:只有本类和子类能访问
例如

class Person{
      public function getname(){}
      private function getage(){}
      protected function getsex(){}
}

上面定义了三个方法,访问级别各不相同;
那PHP内核是如何实现的呢?
经过分析 找到Lex && Yacc的以下代码

class_statement:
                variable_modifiers { CG(access_type) = Z_LVAL($1.u.constant); } class_variable_declaration ';'
        |       class_constant_declaration ';'
        |       method_modifiers function is_reference T_STRING { zend_do_begin_function_declaration(&$2, &$4, 1, $3.op_type, &$1 TSRMLS_CC); } '('
                        parameter_list ')' method_body { zend_do_abstract_method(&$4, &$1, &$9 TSRMLS_CC); zend_do_end_function_declaration(&$2 TSRMLS_CC); }
;

这三个访问控制 会在 method_modifiers这个节点中控制,跟进去最后找到如下代码

member_modifier:
                T_PUBLIC                                { Z_LVAL($$.u.constant) = ZEND_ACC_PUBLIC; }
        |       T_PROTECTED                             { Z_LVAL($$.u.constant) = ZEND_ACC_PROTECTED; }
        |       T_PRIVATE                               { Z_LVAL($$.u.constant) = ZEND_ACC_PRIVATE; }
        |       T_STATIC                                { Z_LVAL($$.u.constant) = ZEND_ACC_STATIC; }
        |       T_ABSTRACT                              { Z_LVAL($$.u.constant) = ZEND_ACC_ABSTRACT; }
        |       T_FINAL                                 { Z_LVAL($$.u.constant) = ZEND_ACC_FINAL; }
;

就是在这里,根据用户的输入然后设置$$.u.constant的值,$$就是返回值
ZEND_ACC_PUBLIC,ZEND_ACC_PROTECTED,ZEND_ACC_PRIVATE这三个定义在
Zend/zend_compile.h中

#define ZEND_ACC_PUBLIC         0x100
#define ZEND_ACC_PROTECTED      0x200#define ZEND_ACC_PRIVATE        0x400
#define ZEND_ACC_PRIVATE        0x400

整个大体流程如下

member_modifier来根据用户输入的关键字相应的设置$$的constant的值,最后会返回给method_modifiers
重点看这里
method_modifiers function is_reference T_STRING { zend_do_begin_function_declaration(&$2, &$4, 1, $3.op_type, &$1 TSRMLS_CC); } ‘(‘
method_modifiers 返回我们设置的访问级别,public,private or protected,
最后 zend_do_begin_function_declaration(&$2, &$4, 1, $3.op_type, &$1 TSRMLS_CC);
执行这个函数,最后一个参数就是method_modifiers所返回的值.
这个函数是我们第三次提到啦..
再进去看一看它的定义
Zend/zend_compile.c

void zend_do_begin_function_declaration(znode *function_token, znode *function_name, int is_method, int return_reference, znode *fn_flags_znode TSRMLS_DC) /* {{{ */ 
{
    省略...
     zend_uint fn_flags;
    省略...
    fn_flags = Z_LVAL(fn_flags_znode->u.constant);
    省略...
    op_array.fn_flags |= fn_flags; 
}

fn_flags是一个临时变量 ,将method_modifiers所返回的访问级别临时存放在这里
最后执行op_array.fn_flags |= fn_flags; 这句代码,将访问级别存放到op里.
在execute执行到此op的时候 就会先去检测此属性是否具有访问权限…

if (fbc->op_array.fn_flags & ZEND_ACC_PUBLIC) {
    //可以访问
} else if (fbc->op_array.fn_flags & ZEND_ACC_PRIVATE) {
    //私有方法,报错
} else if ((fbc->common.fn_flags & ZEND_ACC_PROTECTED)) {
    //保护方法,报错
}

剩下的就是我们所熟悉的PHP的东西了..
没有访问权限就报错..

原文出处:http://www.imsiren.com/archives/420