小编典典

编译器代码建议这是设计使然,尽管我不知道其背后的官方原因是什么。我也不确定要可靠地实现此功能需要花费多少精力,但是目前完成工作的方式肯定存在一些限制。

尽管我对PHP编译器的了解并不广泛,但我将尝试说明我认为的情况,以便您可以发现问题所在。您的代码示例非常适合此过程,因此我们将使用它:

class Foo {

public $path = array(

realpath(".")

);

}

如您所知,这会导致语法错误。这是PHP语法的结果,该语法进行了以下相关定义:

class_variable_declaration:

//...

| T_VARIABLE '=' static_scalar //...

;

因此,在定义变量值(例如)时$path,期望值必须与静态标量的定义匹配。毫不奇怪,考虑到静态标量的定义还包括其值也是静态标量的数组类型,这有点用词不当:

static_scalar: /* compile-time evaluated scalars */

//...

| T_ARRAY '(' static_array_pair_list ')' // ...

//...

;

让我们先假设语法是不同的,并且类变量delcaration规则中的注释行看起来更像以下内容,它将与您的代码示例相匹配(尽管会破坏有效的赋值):

class_variable_declaration:

//...

| T_VARIABLE '=' T_ARRAY '(' array_pair_list ')' // ...

;

重新编译PHP之后,示例脚本将不再因该语法错误而失败。相反,它将因编译时错误 “ Invalid binding type”

而失败。由于代码现在基于语法是有效的,因此这表明实际上在编译器设计中存在某些特定问题,这些问题会引起麻烦。为了弄清楚是什么,让我们暂时恢复原始语法,并假设代码示例的有效分配为$path

= array( 2 );。

使用语法作为指导,可以在解析此代码示例时逐步浏览编译器代码中调用的操作。我省略了一些不太重要的部分,但是过程看起来像这样:

// ...

// Begins the class declaration

zend_do_begin_class_declaration(znode, "Foo", znode);

// Set some modifiers on the current znode...

// ...

// Create the array

array_init(znode);

// Add the value we specified

zend_do_add_static_array_element(znode, NULL, 2);

// Declare the property as a member of the class

zend_do_declare_property('$path', znode);

// End the class declaration

zend_do_end_class_declaration(znode, "Foo");

// ...

zend_do_early_binding();

// ...

zend_do_end_compilation();

尽管编译器在这些各种方法中做了很多事情,但重要的是要注意一些事情。

呼叫会zend_do_begin_class_declaration()导致呼叫get_next_op()。这意味着它将向当前操作码数组添加新的操作码。

array_init()并且zend_do_add_static_array_element()不生成新的操作码。而是立即创建该数组并将其添加到当前类的属性表中。方法声明通过中的特殊情况以类似的方式工作zend_do_begin_function_declaration()。

zend_do_early_binding() 消耗 电流操作码阵列上的最后一个操作码,检查其设置为NOP之前,以下类型之一: ZEND_DECLARE_FUNCTION

ZEND_DECLARE_CLASS

ZEND_DECLARE_INHERITED_CLASS

ZEND_VERIFY_ABSTRACT_CLASS

ZEND_ADD_INTERFACE

请注意,在最后一种情况下,如果操作码类型不是预期的类型之一,则会引发错误- “无效的绑定类型”

错误。由此可见,允许以某种方式分配非静态值会导致最后一个操作码不是预期的。那么,当我们将非静态数组与经过修改的语法一起使用时,会发生什么呢?

array_init()编译器不调用而是准备参数和调用zend_do_init_array()。依次调用get_next_op()并添加一个新的INIT_ARRAY操作码,产生如下所示的内容:

DECLARE_CLASS 'Foo'

SEND_VAL '.'

DO_FCALL 'realpath'

INIT_ARRAY

这就是问题的根源。通过添加这些操作码,zend_do_early_binding()将获得意外的输入并引发异常。由于早期绑定类和函数定义的过程似乎是PHP编译过程不可或缺的一部分,因此不能仅仅忽略它(尽管DECLARE_CLASS的生产/消耗有些混乱)。同样,尝试内联评估这些其他操作码也是不切实际的(您无法确定给定的函数或类是否已解决),因此无法避免生成操作码。

潜在的解决方案是建立一个新的操作码数组,该数组的作用域为类变量声明,类似于处理方法定义的方式。这样做的问题是决定何时评估这样的一次运行序列。当包含该类的文件被加载,第一次访问该属性或构造该类型的对象时,会完成该操作吗?

正如您所指出的那样,其他动态语言也找到了一种处理这种情况的方法,因此做出决定并使之生效并非并非不可能。据我所知,在PHP的情况下这样做不是一站式解决方案,而语言设计人员似乎已经决定,此时不值得这样做。

2020-05-26

php函数方法属性吗,为什么PHP属性不允许使用函数?相关推荐

  1. js中函数,方法,事件对比区分,什么是方法,什么是函数

    微信小程序开发交流qq群   581478349    承接微信小程序开发.扫码加微信. 正文: 简单的理解:函数是运行在本地的,方法是公用的.  事件是开关,通过某某事件触发某个函数 通常命名规范 ...

  2. C语言题解:用二分法思想求解10个元素中某个元素的下标(包含函数方法)

    算法思想:用左下标和右下标之和除二得出中间下标值,再通过与所求元素比较,缩小范围,最后实现左下右下标相等,即找出所求下标.代码实现如下: #include <stdio.h> int ma ...

  3. python查看某个函数方法具体有哪些参数怎么做

    一.目标确立 我想知道python的某个函数方法具体有哪些参数 二.实现步骤 (1)在jupyter notebook中查看某个函数方法具体有哪些参数: 调用help()函数,如:我想知道pandas ...

  4. python查看类的属性和方法_Python 获取对象的属性和方法—dir 函数

    工作中,我们使用一些之前没用到过的模块,使用时需要了解一下这个模块中的一些类的方法或属性,怎么做呢?目前我比较常用的两款IDE"Pycharm"和"VSCode" ...

  5. 在学习EasyX过程中,遇到“没有与参数列表匹配的重载函数loadimage”,修改解决方案字符集属性无效后的解决方法

    在学习EasyX过程中,遇到"没有与参数列表匹配的重载函数loadimage"的问题,在网上查询后,很多人给出的方法是--修改解决方案字符集属性. 解决"E0304&qu ...

  6. Vue——计算属性(计算属性简介、计算属性和方法的区别:(面试)、关于计算属性 函数什么情况下调用、案例)

    目录 计算属性(面试) 1.计算属性简介 2.计算属性和方法的区别:(面试) 3.关于计算属性 函数什么情况下调用​​​​​​​ 4.案例:购物车页面计算总价 计算属性(面试) 1.计算属性简介 把c ...

  7. Python零基础教程:函数和类内建魔法属性

    前言 关于对象的魔法方法我们已经讲得太多,但是对于类或函数内建的魔法属性和功能我们涉及较少,下面系统了解一下类和函数的内建属性. 查看内建属性 class Person(object):passdef ...

  8. oclick vue 传参 函数_详解Vue计算属性和侦听属性

    关注[搜狐技术产品]公众号,第一时间获取技术干货 作者介绍: 本期特邀作者:浪里行舟 Github博客2600 star作者,专注于前端领域.个人公众号:「前端工匠」,致力于打造适合初中级工程师能够快 ...

  9. Linux系统编程----15(线程与进程函数之间的对比,线程属性及其函数,线程属性控制流程,线程使用注意事项,线程库)

    对比 进程 线程 fork pthread_create exit (10) pthread_exit (void *) wait (int *) pthread_join (,void **)阻塞 ...

  10. C#属性详解及属性与函数间的对比

    属性:get { //读属性代码 } set { //写属性代码 } public class Person { private string name; public string Name {   ...

最新文章

  1. 山沟沟里的实业路(3)
  2. 实现GridView的插入功能
  3. java的原生数据类型_Java中的8种原生数据类型(Primitive Data Types)分析
  4. 使用Python可以做些什么
  5. 比反射更快:委托 第3部分
  6. python实时数据存储与显示_利用python进行数据加载和存储
  7. Tomcat+Spring+Quartz Restart or shutdown error
  8. 数据增量更新定义_技术资讯 | TiDB在准实时数据仓库中的实践
  9. 应对用户需求的四个要点-企业数字化转型外部:驱动力之客户篇...
  10. OpenStack单点部署及使用简单教程(附:部署好的VMware虚拟机)
  11. Centos7.6环境使用kubeadm部署kubernetes1.18.4
  12. 单片机C语言,从小白到菜鸟进阶教程(超详细代码解读)
  13. Web应用程序设计(一)——基础开发环境搭建
  14. 超靠谱,一文教会你如何注册申请安徽省实用新型专利
  15. 泛微 E9开发视频教程
  16. 淘宝广告数据分析实战!(附代码和100W数据源)
  17. 服务器上qq邮件不能打开方式,qq邮箱打不开解决方法汇总
  18. 【v-charts】折线图
  19. JDBC从入门到精通
  20. 预告:揭秘7*24小时用数学解码交易的神秘玩家,量化交易者——TokenInsight对话首席...

热门文章

  1. aws rds监控慢sql_使用AWS CLI部署AWS RDS SQL Server
  2. cesium 风向数据_风向标; 针对“实时”生产数据SQL Server开发/测试数据库克隆
  3. SQL FILESTREAM与数据库快照,镜像,TDE和日志传送的兼容性
  4. SQL Server事务日志采访问题
  5. 数学之美 与 浪潮之巅
  6. php7 on winxp 支持的模块
  7. Linux高级实用命令
  8. Numpy:通过算数运算取值、替换值
  9. [学习笔记]Javascript可选的分号
  10. LightOJ1171 Knights in Chessboard (II)(二分图最大点独立集)