首页 后端开发 php教程 PHP保留类及特殊类

PHP保留类及特殊类

Jun 21, 2019 pm 03:53 PM

PHP保留类及特殊类

在面向对象语言中,都会内置一些语言内置提供的基本功能类,比如JavaScript中的Array,Number等类,PHP中也有很多这种类,比如Directory,stdClass,Exception等类,同时一些标准扩展比如PDO等扩展中也会定义一些类,PHP中类是不允许重复定义的,所以在编写代码时不允许定义已经存在的类。

同时PHP中有一些特殊的类:selfstaticparent,相信读者对这self和parent都比较熟悉了,而static特殊类是PHP5.3才引入的。

PHP中的static关键字非常多义:

● 在函数体内的修饰变量的static关键字用于定义静态局部变量。

● 用于修饰类成员函数和成员变量时用于声明静态成员。

● (PHP5.3)在作用域解析符(::)前又表示静态延迟绑定的特殊类。

这个关键字修饰的意义都表示"静态",在PHP手册中提到self,parent和static这几个关键字,但实际上除了static是关键字以外,其他两个均不是关键字,在手册的关键字列表中也没有这两个关键字,要验证这一点很简单:

<?php
[var_dump](http://www.php.net/var_dump)(self); // -> string(4) "self"
登录后复制

上面的代码并没有报错,如果你把error_reporting(E_ALL)打开,就能看到实际是什么情况了:运行这段代码会出现“ Notice: Use of undefined constant self - assumed 'self'“,也就是说PHP把self当成一个普通常量了,尝试未定义的常量会把产量本身当成一个字符串,例如上例的”self",不过同时会出一个NOTICE,这就是说self这个标示符并没有什么特殊的。

<?php
[define](http://www.php.net/define)(&#39;self&#39;,"stdClass");
[echo](http://www.php.net/echo) self; // stdClass
登录后复制

不同语言中的关键字的意义会有些区别,Wikipedia上的解释是: 具有特殊含义的标示符或者单词,从这个意义上说$this也算是一个关键字,但在PHP的关键字列表中并没有。 PHP的关键字和C/C++一样属于保留字(关键字),关键字用于表示特定的语法形式,例如函数定义,流程控制等结构。 这些关键字有他们的特定的使用场景,而上面提到的self和parent并没有这样的限制。

self,parent,static类

前面已经说过self的特殊性。self是一个特殊类,它指向当前类,但只有在类定义内部才有效,但也并不一定指向类本身这个特殊类,比如前面的代码,如果放在类方法体内运行,echo self; 还是会输出常量self的值,而不是当前类,它不止要求在类的定义内部,还要求在类的上下文环境,比如 new self()的时候,这时self就指向当前类,或者self::$static_varible,self::CONSTANT类似的作用域解析符号(::),这时的self才会作为指向本身的类而存在。

同理parent也和self类似。下面先看看在在类的环境下的编译吧$PHP_SRC/Zend/zend_language_parser.y:

class_name_reference:
        class_name                      { zend_do_fetch_class(&$$, &$1 TSRMLS_CC); }
    |   dynamic_class_name_reference    { zend_do_end_variable_parse(&$1, BP_VAR_R, 0 TSRMLS_CC); zend_do_fetch_class(&$$, &$1 TSRMLS_CC); }
;
登录后复制

在需要获取类名时会执行zend_do_fetch_class()函数:

void zend_do_fetch_class(znode *result, znode *class_name TSRMLS_DC)
{
    // ...
    opline->opcode = ZEND_FETCH_CLASS;
    if (class_name->op_type == IS_CONST) {
        int fetch_type;
 
        fetch_type = zend_get_class_fetch_type(class_name->u.constant.value.str.val, class_name->u.constant.value.str.len);
        switch (fetch_type) {
            case ZEND_FETCH_CLASS_SELF:
            case ZEND_FETCH_CLASS_PARENT:
            case ZEND_FETCH_CLASS_STATIC:
                SET_UNUSED(opline->op2);
                opline->extended_value = fetch_type;
                zval_dtor(&class_name->u.constant);
                break;
            default:
                zend_resolve_class_name(class_name, &opline->extended_value, 0 TSRMLS_CC);
                opline->op2 = *class_name;
                break;
        }
    } else {
        opline->op2 = *class_name;
    }
    // ...
}
登录后复制

上面省略了一些无关的代码,重点关注fetch_type变量。这是通过zend_get_class_fetch_type()函数获取到的。

int zend_get_class_fetch_type(const char *class_name, uint class_name_len)
{
    if ((class_name_len == sizeof("self")-1) &&
        !memcmp(class_name, "self", sizeof("self")-1)) {
        return ZEND_FETCH_CLASS_SELF;
    } else if ((class_name_len == sizeof("parent")-1) &&
        !memcmp(class_name, "parent", sizeof("parent")-1)) {
        return ZEND_FETCH_CLASS_PARENT;
    } else if ((class_name_len == sizeof("static")-1) &&
        !memcmp(class_name, "static", sizeof("static")-1)) {
        return ZEND_FETCH_CLASS_STATIC;
    } else {
        return ZEND_FETCH_CLASS_DEFAULT;
    }
}
登录后复制

前面的代码是Zend引擎编译类相关操作的代码,下面就到执行阶段了,self,parent等类的指向会在执行时进行获取,找到执行opcode为ZEND_FETCH_CLASS的执行函数:

zend_class_entry *zend_fetch_class(const char *class_name, uint class_name_len, int fetch_type TSRMLS_DC)
{
    zend_class_entry **pce;
    int use_autoload = (fetch_type & ZEND_FETCH_CLASS_NO_AUTOLOAD) == 0;
    int silent       = (fetch_type & ZEND_FETCH_CLASS_SILENT) != 0;
 
    fetch_type &= ZEND_FETCH_CLASS_MASK;
 
check_fetch_type:
    switch (fetch_type) {
        case ZEND_FETCH_CLASS_SELF:
            if (!EG(scope)) {
                zend_error(E_ERROR, "Cannot access self:: when no class scope is active");
            }
            return EG(scope);
        case ZEND_FETCH_CLASS_PARENT:
            if (!EG(scope)) {
                zend_error(E_ERROR, "Cannot access parent:: when no class scope is active");
            }
            if (!EG(scope)->parent) {
                zend_error(E_ERROR, "Cannot access parent:: when current class scope has no parent");
            }
            return EG(scope)->parent;
        case ZEND_FETCH_CLASS_STATIC:
            if (!EG(called_scope)) {
                zend_error(E_ERROR, "Cannot access static:: when no class scope is active");
            }
            return EG(called_scope);
        case ZEND_FETCH_CLASS_AUTO: {
                fetch_type = zend_get_class_fetch_type(class_name, class_name_len);
                if (fetch_type!=ZEND_FETCH_CLASS_DEFAULT) {
                    goto check_fetch_type;
                }
            }
            break;
    }
 
    if (zend_lookup_class_ex(class_name, class_name_len, use_autoload, &pce TSRMLS_CC) == FAILURE) {
        if (use_autoload) {
            if (!silent && !EG(exception)) {
                if (fetch_type == ZEND_FETCH_CLASS_INTERFACE) {
                    zend_error(E_ERROR, "Interface &#39;%s&#39; not found", class_name);
                } else {
                    zend_error(E_ERROR, "Class &#39;%s&#39; not found", class_name);
                }
                }
            }
        }
        return NULL;
    }
    return *pce;
}
登录后复制

从这个函数就能看出端倪了,当需要获取self类的时候,则将EG(scope)类返回,而EG(scope)指向的正是当前类。如果时parent类的话则从去EG(scope)->parent也就是当前类的父类,而static获取的时EG(called_scope),分别说说EG宏的这几个字段,前面已经介绍过EG宏,它可以展开为如下这个结构体:

struct _zend_executor_globals {
    // ...
    zend_class_entry *scope;
    zend_class_entry *called_scope; /* Scope of the calling class */
    // ...
}
 
struct _zend_class_entry {
    char type;
    char *name;
    zend_uint name_length;
    struct _zend_class_entry *parent;
}
#define struct _zend_class_entry zend_class_entry
登录后复制

其中的zend_class_entry就是PHP中类的内部结构表示,zend_class_entry有一个parent字段,也就是该类的父类。在EG结构体中的中called_scope会在执行过程中将当前执行的类赋值给called_scope,例如如下代码:

<?php
class A {
    public [static](http://www.php.net/static) funcA() {
        [static](http://www.php.net/static)::funcB();
    }
}
 
class B {
    public [static](http://www.php.net/static) funcB() {
        [echo](http://www.php.net/echo)  "B::funcB()";
    }
}
 
B::funcA();
登录后复制

代码B::funcA()执行的时候,实际执行的是B的父类A中定义的funcA函数,A::funcA()执行时当前的类(scope)指向的是类A,而这个方法是从B类开始调用的,called_scope指向的是类B,static特殊类指向的正是called_scope,也就是当前类(触发方法调用的类),这也是延迟绑定的原理。

以上是PHP保留类及特殊类的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
1 个月前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
1 个月前 By 尊渡假赌尊渡假赌尊渡假赌
威尔R.E.P.O.有交叉游戏吗?
1 个月前 By 尊渡假赌尊渡假赌尊渡假赌

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

在PHP API中说明JSON Web令牌(JWT)及其用例。 在PHP API中说明JSON Web令牌(JWT)及其用例。 Apr 05, 2025 am 12:04 AM

JWT是一种基于JSON的开放标准,用于在各方之间安全地传输信息,主要用于身份验证和信息交换。1.JWT由Header、Payload和Signature三部分组成。2.JWT的工作原理包括生成JWT、验证JWT和解析Payload三个步骤。3.在PHP中使用JWT进行身份验证时,可以生成和验证JWT,并在高级用法中包含用户角色和权限信息。4.常见错误包括签名验证失败、令牌过期和Payload过大,调试技巧包括使用调试工具和日志记录。5.性能优化和最佳实践包括使用合适的签名算法、合理设置有效期、

描述扎实的原则及其如何应用于PHP的开发。 描述扎实的原则及其如何应用于PHP的开发。 Apr 03, 2025 am 12:04 AM

SOLID原则在PHP开发中的应用包括:1.单一职责原则(SRP):每个类只负责一个功能。2.开闭原则(OCP):通过扩展而非修改实现变化。3.里氏替换原则(LSP):子类可替换基类而不影响程序正确性。4.接口隔离原则(ISP):使用细粒度接口避免依赖不使用的方法。5.依赖倒置原则(DIP):高低层次模块都依赖于抽象,通过依赖注入实现。

解释PHP中晚期静态结合的概念。 解释PHP中晚期静态结合的概念。 Mar 21, 2025 pm 01:33 PM

文章讨论了PHP 5.3中引入的PHP中的晚期静态结合(LSB),从而允许静态方法的运行时分辨率调用以获得更灵活的继承。 LSB的实用应用和潜在的触摸

如何用PHP的cURL库发送包含JSON数据的POST请求? 如何用PHP的cURL库发送包含JSON数据的POST请求? Apr 01, 2025 pm 03:12 PM

使用PHP的cURL库发送JSON数据在PHP开发中,经常需要与外部API进行交互,其中一种常见的方式是使用cURL库发送POST�...

框架安全功能:防止漏洞。 框架安全功能:防止漏洞。 Mar 28, 2025 pm 05:11 PM

文章讨论了框架中的基本安全功能,以防止漏洞,包括输入验证,身份验证和常规更新。

如何在系统重启后自动设置unixsocket的权限? 如何在系统重启后自动设置unixsocket的权限? Mar 31, 2025 pm 11:54 PM

如何在系统重启后自动设置unixsocket的权限每次系统重启后,我们都需要执行以下命令来修改unixsocket的权限:sudo...

自定义/扩展框架:如何添加自定义功能。 自定义/扩展框架:如何添加自定义功能。 Mar 28, 2025 pm 05:12 PM

本文讨论了将自定义功能添加到框架上,专注于理解体系结构,识别扩展点以及集成和调试的最佳实践。

See all articles