深切理解PHP内核(十四)类的积极分子变量和方式

初稿链接:http://www.orlion.ga/1237/

恍如的分子变量在PHP中精神是一个变量,只是这些变量都落于某个类,并且于这些变量是发出访问控制的。

    类的积极分子方法在PHP中精神是一个函数,只是这函数以类的计有,他也许是一个像样方式呢说不定是一个实例方法,并且在这些点子还长了近乎的访问控制。类的积极分子方法是现实性世界实体行为之泛,可以用来兑现类似的行为。

如出一辙、成员变量

    成员变量在编译时一度报到了仿佛的构造被。在编译时类的扬言编译会调用zend_do_begin_class_declaration函数。此函数用来初始化类的核心信息,其中囊括类的分子变量。其调用顺序也[zend_do_begin_class_declaration]–>[zend_initalize_class_data]–>[zend_hash_init_ex]

zend_hash_init_ex(&ce->default_properties, 0, NULL, zval_ptr_dtor_func, persistent_hashes, 0);

    
    因为接近的积极分子变量是保留于HashTable,所以那个数量的初始化使用zend_hash_init_ex函数来进展。

    在声明类的早晚初始化了仿佛的分子变量所于的HashTable,之后要发新的积极分子变量属性声明时,在编译时zend_do_declare_property。函数首先检查成员变量不允的一部分情:

  • 接口中不允许行使成员变量

  • 分子变量不能够具备抽象属性

  • 未克宣称成员变量为final

  • 勿可知重复声明属性

    如果在相近吃以一个特性声明也final:

public final $var

    会报错:Fatal error: Cannot declare property
…这个错误由zend_do_declare_property函数抛来:

if (access_type & ZEND_ACC_FINAL) {
    zend_error(E_COMPILE_ERROR, "Cannot declare property %s::$%s final, the 
final modifier is allowed only for methods and classes",
               CG(active_class_entry)->name, var_name-
>u.constant.value.str.val);
}

    在概念检查并未问题下,函数会展开成员变量的初始化操作。

ALLOC_ZVAL(property);   //  ¾ĘŴ
 
if (value) {    //  ÒʻĻļUɩ ȐďĤ
    *property = value->u.constant;
} else {
    INIT_PZVAL(property);
    Z_TYPE_P(property) = IS_NULL;
}

    在初始化过程被,程序会预先分配内存,如果是成员变量有初始化的数额,则用数据直接赋值给该属性,否则初始化ZVAL,并将该列设置也IS_NULL。在初始化过程就后,程序通过调用zend_declare_property_ex函数将是成员变量添加至指定的类组织中。

    常规的成员变量最后还见面登记到类的default_propertiles字段。在我们平素的办事遭到,可能会见为此非顶上面所说之这些经过,但是咱也许会见采用get_class_vars()函数来查看类的成员变量。此函数返回由接近的默认属性组成的涉嫌数组,这个数组的元素以varname=>value的款型是。其落实核心代码如下:

if (zend_lookup_class(class_name, class_name_len, &pce TSRMLS_CC) == FAILURE) {
    RETURN_FALSE;
} else {
    array_init(return_value);
    zend_update_class_constants(*pce TSRMLS_CC);
    add_class_vars(*pce, &(*pce)->default_properties, return_value TSRMLS_CC);
    add_class_vars(*pce, CE_STATIC_MEMBERS(*pce), return_value TSRMLS_CC);
}

    首先调用zend_lookup_class函数查找名也class_name的好像,并将复制给pce变量。这个查找的长河太核心是一个HashTable的搜函数zend_hash_quick_find,它见面查找EG(class_table)。判断类是否有,如果存在则直归。如果非存,则需判定是否好活动加载,如果得以自行加载,则会加载类后还返回。如果不克找到类似,则回FALSE。如果找到了接近,则初始化返回的屡屡组,更新类的静态成员变量,添加类的分子变量到回的数组。这里针对类的静态成员变量有一个更新的历程,关于这进程我们在脚有关于静态变量中举行连锁介绍。

 

亚、静态成员变量

    类的静态成员变量是负有实例公用的,它归属为这个类似,因此其吗深受做类变量。在PHP的类似组织中,类本身的静态变量是以类似组织的default_static_memebers字段中。

    与普通成员变量不同,类变量可以直接通过类名调用,这吗反映其称作类变量的特别。一个PHP实例:

class Tipi {
    public static $var = 10;
}
 
Tipi::$var;

    通过VLD扩展查看其变化的中间代码:

function name:  (null)
number of ops:  6
compiled vars:  !0 = $var
line     # *  op                           fetch          ext  return  operands
-------------------------------------------------------------------------------
-
-
   2     0  >   EXT_STMT
         1      NOP
   6     2      EXT_STMT
         3      ZEND_FETCH_CLASS                                 :1      'Tipi'
         4      FETCH_R                      static member               'var'
         5    > RETURN                                                   1
 
branch: #  0; line:     2-    6; sop:     0; eop:     5
path #1: 0,
Class Tipi: [no user functions]

    这段中间代码仅仅与Tipi::$var这段调用对应,它同前面的类定义没有多生关系。根据VLD生成的情我们得领略PHP代码:Tipi::$var,生成的中间代码包括ZEND_FETCH_CLASS和FETCH_R。这里只有是一个静态变量的调用,但是她可死成了个别独中间代码。原因:我们要调用一个类似的静态变量,当然如果先期找到这个近乎,然后重新获之仿佛的变量。从PHP源码来拘禁,这是由当编译时该调用了zend_do_fetch_static_member函数,而于这函数中而且调用了zend_do_fetch_class函数,从而会生成ZEND_FETCH_CLASS中间代码。它所对应的施行函数为ZEND_FETCH_CLASS_SPEC_CONST_HANDLER。此函数会调用zend_fetch_class函数(Zend/zend_execute_API.c)。而zend_fetch_class函数最终为会见调用zend_lookup_class_ex函数查找类。

    找到了类似就应该就是查找类的静态成员变量,其最后调用的函数为:zend_std_get_static_property。这里由于第二单参数的品类也ZEND_FETCH_STATIC_MEMBER。这个函数最后是起static_members字段中检索对应之价值返回。而在寻前会和前面一样,执行zend_update_class_constant函数,从而创新此类的有所静态成员变量,静态变量更新流程图:

    图片 1

    

其三、成员方法

    成员方法从精神上来以为是相同种植函数,所以那个储存结构吧与健康函数一样,存储在zend_function结构体中。对于一个好像的差不多只分子方法,它是因HashTable的数据结构存储了差不多个zend_function结构体。和前的积极分子变量一样,在看似声明时成员方法也由此调用zend_initalize_class_data方法,初始化了任何方列表所当的HashTable。

    除去访问控制关键字,一个分子方法以及正常函数是同样的,从语法解析被调用的函数一样(都是zend_do_begin_function_declaration函数),但是该调用的参数有一对两样,第三只参数is_method,成员方法的赋值为1,表示其看成成员方法的属性。在是函数中见面生同等体系的编译判断,比如以接口中不能够声称私有的成员方法。
    在是程序判断后,程序将方直接助长到近似组织的function_table字段,在此之后,又是多少的编译检测。比如接口的有的魔术点子不可知装为非公有,不能够让装置也static,如__call()、__callStatic()、__get()等。

    与成员变量一样,成员方法也来一个返回所有成员方法的函数–get_class_methods()。此函数返回由指定的类似吃定义的不二法门名所做的数组。

 

季、静态成员方法

    类的静态成员方法一般为为做类方法。与静态成员变量不同,静态成员方法及成员方法都存储于近似组织的function_table字段。

class Tipi{
    public static function t() {
        echo 1;
    }
}
 
Tipi::t();

    以上之代码在VLD扩展下别的组成部分中间代码:

number of ops:  8
compiled vars:  none
line     # *  op                           fetch          ext  return  operands
-------------------------------------------------------------------------------
--
   2     0  >   EXT_STMT
         1      NOP
   8     2      EXT_STMT
         3      ZEND_INIT_STATIC_METHOD_CALL                             
'Tipi','t'
         4      EXT_FCALL_BEGIN
         5      DO_FCALL_BY_NAME                              0
         6      EXT_FCALL_END
   9     7    > RETURN                                                   1
 
branch: #  0; line:     2-    9; sop:     0; eop:     7
path #1: 0,
Class Tipi:
Function t:
Finding entry points
Branch analysis from position: 0

    从以上之情节可视整个静态成员方法的调用是一个先查找法重复调用的长河。而对于调用操作,对应之中间代码为ZEND_INIT_STATIC_METHOD_CALL。由于类名和方式名都是常量,于是我们好了解中间代码对应之函数是ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CONST_HANDLER。在这函数中,它见面首先调用zend_fetch_class函数,通过类名在EG(class_table)中查找类,然后再度履行静态方法的落方式。

if (ce->get_static_method) {
    EX(fbc) = ce->get_static_method(ce, function_name_strval, 
function_name_strlen TSRMLS_CC);
} else {
    EX(fbc) = zend_std_get_static_method(ce, function_name_strval, 
function_name_strlen TSRMLS_CC);
}

    如果类似组织被的get_static_method方法有,则调用此措施,如果不存在,则调用zend_std_get_static_method。在PHP的源码中get_static_method方法一般都是NULL,这里我们要查看zend_std_get_static_method函数。此函数会寻找ce->function_table列表,在寻找到艺术后检查措施的访问控制权限,如果未允看,则报错,否则回函数结构体。

相关文章