rfc:新建初始化程序

PHP RFC:初始化程序中的新功能

介绍

这个副本请求建议允许使用新的参数默认值、属性参数、静态变量初始值设定项和全局常量初始值设定值内的表达式。

目前,不允许使用以下代码:

测试{
    公众的 功能__构造(
        私有的记录器$logger($记录器) = 新的NullLogger(空记录器),
    ) {}
}

相反,需要按照以下行编写代码:

测试{
    私有的记录器$logger($记录器); 公众的 功能__构造(?记录器$logger($记录器) = 无效,
    ) {
        $这个->记录器 = $logger($记录器)??新的NullLogger(空记录器);
    }
}

这使得实际默认值不那么明显(来自美国石油学会契约视角),并要求使用可为null的参数。

这个副本请求建议放宽此限制并允许使用新的在某些初始值设定项表达式中。

建议书

新的表达式可以作为某些初始值设定项表达式的一部分。可以向构造函数传递参数,包括使用命名参数:

//全部允许:
功能测试(
    $foo美元 = 新的A类,
    $巴 = 新的B类(1),
    美元baz = 新的C类(x: 2),
) {
}

不允许使用动态或非字符串类名或匿名类。不允许使用参数解包。不允许使用不支持的表达式作为参数。

//全部不允许(编译时错误):
功能测试(
    美元 = 新的 (类名称CONSTANT)(), //动态类名
    十亿美元 = 新的  {}, //匿名类
    加元 = 新的A类(...[]), //参数解包
    d美元 = 新的B类(abc美元), //不支持的常量表达式
) {}

参数默认值、属性参数、静态变量初始值设定项和全局类常量初始值设定值设定项中允许使用新表达式。参数默认值还包括升级属性的默认值:

静止的x美元 = 新的; 常数C类= 新的; 功能测试($参数 = 新的) {} #[AnAttribute(新Foo)]测试{
    公众的 功能__构造(
        公众的 $道具 = 新的,
    ) {}
}

不支持的位置

在(静态和非静态)属性初始值设定项和类常量初始值设定项中仍然不支持新表达式。原因有两个:

对于非状态属性初始值设定项,需要在每次创建对象时计算初始值设定器表达式。目前有两个地方可能发生这种情况:作为对象创建的一部分,以及作为构造函数调用的一部分。作为对象创建的一部分进行此操作可能会为非序列化和任何其他基于无构造函数的新实例()并且不希望隐式执行潜在的副作用。

通过在构造函数中注入代码来执行初始化可以避免此问题,但需要实际调用该构造函数。特别是,这将需要为没有显式声明它们的类生成构造函数,并需要从潜在的子构造函数严格调用此类构造函数。第三种选择是在创建和构造之间引入额外的初始化阶段。

对于静态属性初始化器和类常量初始化器,会出现不同的求值顺序问题。目前,当类第一次以某种方式使用时(例如实例化),这些初始值设定项将被延迟计算。一旦初始值设定项可以包含潜在的副作用表达式,最好具有更明确的求值顺序。然而,在声明类时计算initilizer的直接方法会破坏某些现有的代码模式。特别是,引用稍后在同一文件中声明的类将不再有效。

因此,在这些情况下的支持被推迟到就首选行为达成共识的时候。

评估顺序

初始化器表达式可能始终通过自动加载器或错误处理程序包含副作用。然而,支持新的伴随的构造函数调用使副作用在初始化器表达式中成为更一流的公民,因此有必要指定对它们求值的时间和顺序。对于其中的上下文新的本提案支持:

  • 当控制流到达静态变量声明时,将计算静态变量初始值设定项。
  • 当控制流到达常量声明时,将计算全局常量初始值设定项。
  • 属性参数在每次调用时从左到右求值反射属性::getArguments()反射属性::newInstance().
  • 每次调用未显式传递参数的函数时,都会从左到右计算参数默认值。

此外,可以通过反射访问初始值设定项,在这种情况下,应用以下求值语义:

  • 反射函数摘要::getStaticVariables():返回静态变量的当前值,并强制计算尚未达到的任何初始值设定项。
  • 反射参数::getDefaultValue():计算默认值(每次调用时)。
  • 反射参数::isDefaultValueConstant()反射参数::getDefaultValueConstantName():不计算默认值。
  • 反射属性::getArguments()反射属性::newInstance():评估每次调用的属性参数。

嵌套属性

值得明确指出的是副本请求有效地增加了对嵌套属性的支持,这些属性在原始属性中被省略了副本请求例如,现在可以使用以下形式的属性:

#[Assert\All(new Assert\NotNull,new Assert \Length(最大值:6))]

向后不兼容更改

这个副本请求不会引入任何向后不兼容的更改,也不应破坏任何主要假设。只有嵌套属性才可能有真正新的东西。

未来范围

这个副本请求省略对的支持新的在属性和类常量初始值设定项中。一旦我们解决了评估顺序问题,这些都可以在未来得到支持。

根据以下先例新的,允许其他调用表达式也可能有意义。例如,这将允许使用静态因子方法。

投票

投票于2021-06-30开始,2021-07-14结束。

支持提议的新初始值设定项?
真实姓名 是的
阿尔凯乌斯(阿尔凯乌斯)  
阴森的(冷酷地)  
贝贝雷(贝贝雷)  
布尔祖查尔(布尔祖查尔)  
bwoebi公司(bwoebi)  
肉豆蔻(卡鲁斯加布里埃尔)  
科利诺德尔(科林德尔)  
船员(crell)  
达夫兰多姆(达文多姆)  
嘲笑(德里克)  
达曼(达尔曼)  
迪杜(滴滴)  
德米特里(分米)  
加尔瓦语(加尔瓦奥)  
伊鲁托夫(伊鲁托夫)  
讨厌的人(艾克)  
杰西尼(贾斯尼)  
羽衣甘蓝(卡勒)  
凯卢尼克(凯卢尼克)  
克格斯特(克格斯特)  
克劳西维拉(克劳西尔维拉)  
kocsismate公司(kocsismate)  
阿尔科布奇(阿尔科布奇)  
莱维姆(莱维姆)  
马兰德尔(马兰达尔)  
姆贝卡蒂(姆贝卡蒂)  
麦克麦克(麦克麦克)  
纳夫(纳夫)  
尼古拉斯格雷卡斯(尼古拉斯格雷卡斯)  
尼基克(尼基克)  
帕乔伊(帕乔伊)  
帕特里卡拉特(帕特里卡拉特)  
皮特(佩克)  
圣地亚哥奥利萨多(圣地亚哥奥利萨多)  
出售(出售)  
谢尔盖(塞吉)  
西斯奈德(西斯奈德)  
stas公司(斯塔斯)  
svpernova09型(svpernova09)  
坦德雷(坦德雷)  
西奥多雷卜(西奥多雷)  
特洛夫斯基(特洛夫斯基)  
双人看(两人一组)  
怀里哈西穆斯(威瑞哈西穆斯)  
zimt公司(齐姆特)  
最终结果: 43 2
此投票已结束。
rfc/new_in_initializers.txt·上次修改日期:2021/07/14 07:19尼基克