• PHP学习笔记(二):类结构之(静态)成员变量与(静态)方法


    第一组问题:

    1.成员变量与静态成员变量可否同名;

    2.类的成员变量和静态成员变量交换访问方式能否访问到。

    第二组问题:

    1.成员方法与静态成员方法能否同名;
    2.成员方法或静态成员方法是否可以与成员变量或静态成员变量同名;
    3.如果交换访问方式是否可以成功访问。

    实验准备:

    class Test{
        public static $sv = 1;
        public $pv = 2;
        
        public static function sv(){
            echo 'static function sv.<br>';
        }
        public function pv(){
            echo 'normal function pv.<br>';
        }
    }

    第一组问题实验:

    echo Test::$sv;//1
    echo Test::$pv;//Fatal error: Uncaught Error: Access to undeclared static property: Test::$pv
    $test = new Test();
    echo $test->sv;//空白
    var_dump($test->sv);//NULL

    1.成员变量与静态成员变量不能同名;
    2.交换访问方式不能访问到

    第二组问题实验:

    Test::sv();//static function sv.
    Test::pv();//normal function pv.
    $test = new Test();
    $test->sv();//static function sv.
    $test->pv();//normal function pv.

    1.成员方法与静态成员方法不能同名;
    2.成员方法/静态成员方法可以与成员变量/静态成员变量同名;
    3.交换访问方式可以访问得到,但不推荐交换调用。

    从类的存储结构出发理解以上问题:

    //Zendzend.h:116
    struct _zend_class_entry {
        //......省略部分内容
        int default_properties_count;
        int default_static_members_count;
        zval *default_properties_table;
        zval *default_static_members_table;
        zval *static_members_table;
        HashTable function_table;
        HashTable properties_info;
        HashTable constants_table;
        //......又省略大部分内容
    };

    1. 类的成员变量数组(zval *default_properties_table)和静态成员变量数组(zval *default_static_members_table)虽然是类结构体的不同属性,但属性的访问均通过(HashTable properties_info)来查找(参见大牛分享的:PHP7类结构分析)。简单来说就是:

    静态成员变量:根据属性名在properties_info中找到属性在静态变量数组中的下标,再根据下标去类结构的default_static_members_table中取值,静态变量的操作在类空间内,各实例对象共享;

    普通成员变量:根据属性名在properties_info中找到属性在对象空间的偏移(普通成员变量的操作对应于类的实例对象,各个对象有自己独立的空间),根据该偏移取到对象普通成员变量值。

    (1)不能同名是因为均需通过属性名在同一个HashTable中查找;

    (2)不能交换访问是因为

    静态变量访问会执行zend_object_handlers.c中的zend_std_get_static_property方法,通过属性名在类的properties_info中找到对应的zend_property_info,通过其flags判断访问的属性类型是否为静态,若不是静态的会抛出我们看到的异常。

    普通成员变量访问会执行zend_object_handlers.c中的zend_std_read_property方法,在其中调用zend_get_property_offset方法时判断了要访问的属性如果时静态的,则抛出E_NOTICE级别的错误,再后面的处理还没看懂。

    2. 成员方法与静态成员方法存于类结构体的同一属性(HashTable function_table)中,所以不能重名;

    可以交换访问方式的原因

    (1)调用静态成员方法会执行zend_object_handlers.c中的zend_std_get_static_method方法,从类的function_table中查找到对应方法后会判断如果方法不是静态的将抛出异常,前提是满足预处理指令#if MBO_0,它的含义暂不清楚,猜测和php设置的错误级别有关,经测试,将error_reporting设置为E_ALL时,将抛出如下错误:

    Deprecated: Non-static method Test::pv() should not be called statically

    (2)用普通成员方法调用会执行zend_object_handlers.c中的zend_std_get_method方法,其中并未特别处理静态方法的情况,所以可以访问到静态方法。

  • 相关阅读:
    hdu 4107 Gangster 线段树(成段更新)
    hdu 3037 Saving Beans (lucas定理)
    hdu 3944 DP? (Lucas 定理)
    hdu 5038 Grade 水
    ASP.NET Core 配置 MVC
    ASP.NET Core 静态文件
    ASP.NET Core 异常和错误处理
    ASP.NET Core 中间件
    ASP.NET Core 项目配置 ( Startup )
    ASP.NET Core 基本项目目录结构
  • 原文地址:https://www.cnblogs.com/ling-diary/p/9229754.html
Copyright © 2020-2023  润新知