荷花是什么生肖| 左卵巢囊性结构是什么意思| 牙齿上有黑点是什么原因| 女生掉头发严重是什么原因| 1级高血压是什么意思| 牛奶什么时间喝最好| 肝气不足吃什么中成药| 做眉毛有什么危害| 4月15号是什么星座| 膀胱ca是什么意思| 肝损伤吃什么药| 男人得了hpv有什么症状| 梦见背死人是什么意思| 车船税是什么意思每年都交吗| 尿失禁是什么症状| 益母草能治什么病| 结婚送什么礼物最合适| 早上起床口臭是什么原因| 变性乙醇是什么东西| 男人腰疼是什么原因| 什么人不能吃洋葱| cm是什么意思| 亲嘴会传染什么病| 粥米是什么米| 青色是什么色| 梦见摘辣椒是什么意思| 阴道壁是什么样的| 胜字五行属什么| 再障性贫血是什么病| 守望先锋是什么类型的游戏| 左是什么结构| 小孩子睡觉流口水是什么原因| 阑珊是什么意思| 程门立雪是什么意思| 孕妇梦见别人怀孕是什么意思| 财运亨通是什么意思| 医院五行属什么| 朱元璋长什么样| 家里停电了打什么电话| 胆囊炎可以吃什么水果| 额头老出汗是什么原因| 李子吃了有什么好处| 宝宝胀气是什么原因引起的| 什么旺水命| amass是什么牌子| 做爱为什么舒服| 美工是做什么的| 肩周炎口服什么药最好| 俄罗斯信奉的是什么教| bpd是胎儿的什么| 军国主义是什么意思| 气结是什么意思| 驾驶证c1和c2有什么区别| 平安对什么| 释放天性是什么意思| 倒着走路有什么好处| 什么人容易得天疱疮| 胰岛素偏低是什么原因| 牙齿痛吃什么药最管用| 西洋参泡水喝有什么功效| 为什么胸口疼| 血氧低吃什么提高的快| 梦见葱是什么意思| 客家人是什么意思| 人中深的女人代表什么| 白葡萄酒配什么食物| 安全是什么| 输卵管囊肿是什么原因引起的| 稳重什么意思| 子宫肌瘤有什么症状表现| 特别的意思是什么| 芝士是什么味道| hb医学上是什么意思| 西太后手表什么档次| 1994年什么命| torch是什么意思| 猫什么时候打疫苗| 落枕是什么意思| 转移酶偏高是什么原因| 处女男和什么星座最配| 肖可以加什么偏旁| 低钠盐适合什么人吃| 坐疮是什么样的图片| 蠼螋吃什么| 木木耳朵旁是什么字| 吃什么水果会变白| 医学上cr是什么意思| 宫颈多发纳氏囊肿是什么意思| 璋字五行属什么| 水痘疫苗什么时候接种| alan英文名什么意思| 化疗前要做什么检查| 哺乳期什么东西不能吃| saba是什么药| 蚊子爱咬什么样的人| 女人白带多是什么原因| prada是什么品牌| 经变是什么意思| 空前绝后是什么生肖| 关节退行性变是什么意思| 五行缺水是什么意思| 西咪替丁是什么药| 检查是否怀孕要做什么检查| 阿sir什么意思| 老鼠屎长什么样子| 临终关怀的目的是什么| 女性黄体期是什么意思| 鱼漂什么牌子的好| 结节性甲状腺肿是什么意思| 梦见要账是什么意思| 为什么会心肌缺血| 女人最想要什么| 西洋参有什么功效和作用| 自助餐是什么意思| cvt是什么意思| 长一根白眉毛预示什么| 口干舌燥吃点什么药| 一米阳光是什么意思| 地龙是什么东西| 雅漾属于什么档次| 鼻子出血是什么原因引起的| nilm是什么意思| 燕窝是什么做的| 为什么会勃起| 腿麻木是什么原因引起的| 神甫是什么意思| 什么是强迫症有哪些表现| 赊账是什么意思| 女性吃金蝉有什么好处| havva是什么牌子| 瞑眩反应是什么意思| 五角硬币是什么材质| 凤辇是什么意思| 早期复极是什么意思| 慢性胰腺炎吃什么药| 阿莫西林治疗什么| 不惑之年是什么意思| 颞下颌关节挂什么科| 逍遥丸的功效和作用是什么| 头晕目眩是什么原因| 720是什么意思| 纪委是做什么的| 什么什么各异| 朴树是什么树| 什么是溶血| 小孩舌头发白什么原因| 胃热口干口苦口臭吃什么药好| 属龙五行属什么| 控评是什么意思| 心脏病吃什么药| 卵巢多囊样改变是什么意思| 胃烧心是怎么回事吃什么药| 普洱茶适合什么季节喝| 隐睾是什么意思| 人体缺钾是什么原因引起的| 边什么边什么| 来姨妈可以吃什么水果| 面部痒是什么原因| 讥讽的笑是什么笑| 北齐是什么朝代| 孙悟空叫什么名字| 平衡是什么意思| 撸猫是什么意思| 天五行属性是什么| 胃溃疡能吃什么| 见血是什么兆头| 抹茶是什么茶叶做的| 黑发晶五行属什么| 苹果补充什么维生素| yn是什么牌子| 阿米巴病是什么病| 肌红蛋白偏低说明什么| 为什么会痛经| 梦见病人好了什么预兆| 一本万利是什么生肖| 趴在桌子上睡觉有什么坏处| 千岛酱是什么味道| 望闻问切什么意思| 眼睛疼滴什么眼药水| 肾结石有什么症状哪里疼| 梦见双头蛇是什么征兆| 无可奈何是什么生肖| 什么情况啊这是| 脸一边大一边小是什么原因| 蜜蜂为什么要采蜜| 梦到自己杀人是什么意思| 脑膜炎是什么病严重吗| 为什么牙龈老是出血| 20属什么| 熟石灰是什么| 临床路径是什么意思| 黄芪不适合什么人吃| 痰核流注什么意思| 阿胶是什么做的| 四大皆空是指什么| 胸片是什么| 蜻蜓点水是什么行为| 梦见刀是什么意思| 萧字五行属什么| 咽炎吃什么消炎药最好| 龙和什么属相最配| 笔芯是什么意思| 凝血五项是检查什么的| 芒果不能和什么一起吃| dhea是什么| 吸毒什么感觉| joan是什么意思| 嫌恶是什么意思| 一个马一个襄念什么| 鬼迷日眼是什么意思| 硬核什么意思| 睡眠不好总做梦是什么原因| 胆囊炎看什么科室| 跳大神是什么意思| 胃痉挛有什么症状表现| 农历正月初一是什么节日| 梦到自己长白头发是什么意思| 感统训练是什么| 现象是什么意思| 鲁迅的真名叫什么| 神经性耳聋是什么原因造成的| 郁郁寡欢什么意思| 毛囊炎是什么症状图片| 什么的哲理| 红薯什么时候掐尖| 心脏供血不足吃什么| 5月24日什么星座| 甲亢都有什么症状| 宾字五行属什么| 抠鼻表情是什么意思| 脸上长痣是什么原因造成的| 看皮肤挂什么科| 苜蓿是什么| 射手女跟什么星座最配| 什么是白虎| 酚咖片是什么药| 额头反复长痘是什么原因| 玩票是什么意思| 女人内心强大说明什么| 属龙的守护神是什么菩萨| 鱼翅是什么东西| 掰弯了是什么意思| 乌梅是什么水果做的| rb是什么| 痔疮痒痒的是什么原因| 做妇科检查前需要注意什么| 甲亢什么不能吃| 年糕是什么做的| cyl是什么意思| 珊瑚虫属于什么动物| 衣原体感染吃什么药| 肌肉痛是什么原因| 幽门螺杆菌抗体阳性什么意思| 足本是什么意思| 梦见猫死了是什么意思| 口腔溃疡用什么药| 羊内腰和外腰分别是什么| 冥是什么意思| 一花一世界下一句是什么| 经信局是做什么的| 脚转筋是什么原因引起的| 嘴唇红肿是什么原因| 师夷长技以制夷什么意思| 史莱姆是什么意思| 百度
rfc:property-capture

法国妈妈的5大黄金育儿守则

Introduction

百度 FaceID也不安全如今,警方试图利用苹果最新推出的FaceID技术解决死者的手机。

This RFC proposes the addition of an inline syntax for lexical (captured) variables when declaring anonymous classes in PHP. The goal is to simplify anonymous class declarations and make them more concise by allowing developers to capture variables from the outer scope directly.

Anonymous classes were introduced in PHP 7.0, using a syntax that allows declaring a class definition and constructing an instance in a single statement. However, unlike anonymous functions, it is not easy to “capture” values from the parent scope for use inside the class; they can only be passed in via an explicit constructor or other method.

This RFC proposes a “property capture” syntax, where a property can be declared and initialised with $instance = new class use($captured) {}; Optional access modifiers, type, and renaming are also supported, e.g. $instance = new class use($localName as private readonly int $propertyName) {};

Semantics

Capturing variables into an anonymous class instance requires two things:

  1. A way to refer to the captured variables inside the class definition, which is compiled once, when the statement is first run
  2. A way to associate values with these variables for a particular instance, which will vary each time the statement is run

Rather than inventing new syntax and semantics for these, this proposal reuses existing object properties and constructor parameters, as follows:

  1. If a use clause is present, generate an empty constructor which will be added to the anonymous class.
  2. For each captured variable in the use clause, add it as a parameter to the constructor.
  3. Declare a property with the same name as the captured variable in the anonymous class, unless renamed in the use clause (see below).
  4. Set the default visibility of the property to public and the default type to mixed if not specified in the use clause (see below).
  5. In the constructor body, assign the captured variable to the corresponding property.
  6. When creating an instance of the anonymous class, pass the variables listed as parameters to the constructor.

The implementation reuses a lot of mechanics from the existing Constructor Property Promotion mechanism, but this is considered an implementation detail, not a functional guarantee.

Syntax

A new use clause is introduced, immediately after the keywords “new class”, with the syntax use ([&]<var-name> as <modifiers> <type> <property-name>, ...). The <modifiers>, <type>, and <property-name> are all optional; if none is specified, the “as” keyword must be omitted.

Basic Form

The simplest form of property capture resembles the capture list of anonymous functions:

$foo = 1;
$bar = 2;
$anon = new class use ($foo, $bar) {};

This declares a class with public untyped properties $foo and $bar, and creates an instance populating them from the outer variables $foo and $bar. In other words, it is equivalent to this:

$foo = 1;
$bar = 2;
$anon = new class($foo, $bar) {
    var $foo;
    var $bar;
 
    public function __construct($foo, $bar) {
        $this->foo = $foo;
        $this->bar = $bar;
    }
};

Renaming

By default, the property takes the same name as the outer variable, but this can be over-ridden using the syntax $varName as $propName. This also allows the same local variable to be captured as the initial value for more than one property. For example:

$foo = 1;
$bar = 2;
$anon = new class use ($foo as $one, $bar as $two, $bar as $three) {};

Is equivalent to:

$foo = 1;
$bar = 2;
$anon = new class($foo, $bar, $bar) {
    var $one;
    var $two;
    vat $three;
 
    public function __construct($one, $two, $three) {
        $this->one = $one;
        $this->two = $two;
        $this->three = $three;
    }
};

Modifiers and Type

The as keyword can also be used to modify the visibility and/or type of the declared property, either instead of or as well as renaming the property.

The modifiers allowed are the same as for Constructor Property Promotion, which is used internally to declare the properties; that is currently:

  • One of public, protected, or private
  • Optional readonly, which must be combined with a type specification
  • A type specification

For example:

$foo = 1;
$bar = 2;
$anon = new class use ($foo as private, $bar as protected readonly int, $bar as ?int $alsoBar) {};

Is equivalent to:

$foo = 1;
$bar = 2;
$anon = new class($foo, $bar, $bar) {
    private $foo;
    protected readonly int $bar;
    var ?int $alsoBar;
 
    public function __construct($foo, $bar, $alsoBar) {
        $this->foo = $foo;
        $this->bar = $bar;
        $this->alsoBar = $alsoBar;
    }
};

Capture by Reference

It is possible to capture a variable by reference, by prefixing it with &. For example:

$foo = 1;
$anon = new class use (&$foo as $fooProp) {};
$foo = 2;
echo $anon->fooProp;

Will print 2. It is equivalent to:

$foo = 1;
$anon = new class($foo) {
    var $one;
 
    public function __construct(&$one) {
        $this->one =& $one;
    }
};
$foo = 2;
echo $anon->fooProp;

Examples

TODO - expand

Create a struct-like object with readonly public properties:

$id = get_next_id();
$name = get_name();
$user = new readonly class use ($id, $name) {};
echo "{$user->id}: {$user->name}";
$user->id = 42; // ERROR: Cannot modify readonly property $id

Decorate a PSR-3 logger, adding some context to all entries logged:

use Psr\Log\{LoggerInterface,LoggerTrait};
 
function decorate_logger(LoggerInterface $logger, string $contextKey, mixed $contextValue): LoggerInterface {
   return new class 
        use ($logger as private $innerLogger, $contextKey as private, $contextValue as private) 
        implements LoggerInterface
   {
        public function log($level, string|\Stringable $message, array $context = []): void {
            $context[$this->contextKey] = $this->contextValue;
            $this->innerLogger->log($level, $message, $context);
        }
   };
}

Reflection

The constructor, its parameters, and the properties, all appear as normal if the anonymous class is reflected, but can be detected with two new methods:

  • ReflectionParameter::isCaptured(): bool
  • ReflectionProperty::isCaptured(): bool

Although internally they are declared using Constructor Property Promotion, the parameters and properties return false from ReflectionParameter::isPromoted and ReflectionProperty::isPromoted, as they are not written that way by the user.

The generated constructor itself is not marked, partly due to implementation concerns that a limited number of bits remain available in the fn_flags bitmask.

Restrictions

The following new errors follow from the use of properties, rather than a new mechanism, to access the captured values:

  • “Redefinition of captured property”, e.g. new class use($foo, $foo) {} or new class use($foo as $a, $bar as $a) {}
  • “Captured property $a conflicts with existing property”, e.g. new class use($foo) { public $foo; }

The following new errors follow from the current implementation's use of a generated constructor:

  • “Cannot declare custom constructor for anonymous class with captured properties”, e.g. new class use($foo) { public function __construct() {} }
  • “Cannot pass constructor arguments to anonymous class with captured properties”, e.g. new class($foo) use($bar) {}

Various alternatives to this restriction exist, discussed below. Throwing an Error now does not rule out any of these alternatives being implemented in future versions.

Current Workaround

The restrictions on custom constructors can be worked around by adding a normal instance method, and calling it immediately.

That is, given a current definition like this:

$anon = new class($a, $b, $c) extends SomeOtherClass {
    private $a;
    public function __construct($a, $b, $c) {
        $this->a = $a;
        do_something($b);
        parent::__construct($c);
    }
};

You could instead write this:

$anon = new class use($a) extends SomeOtherClass {
    public function init($b, $c) {
        do_something($b);
        parent::__construct($c);
    }
};
$anon->init($b, $c);

Alternative 1: Merging Constructors

It would be possible in principle to detect an existing constructor, and merge both its argument list and body with the generated code. That is, the above example could be written as:

# NOT supported in current proposal
$anon = new class($b, $c) use($a) extends SomeOtherClass {
    public function __construct($b, $c) {
        do_something($b);
        parent::__construct($c);
    }
};

The principle difficulty here is finding a point in the compilation process where the explicit constructor can be easily detected but still modified.

It also leads to additional error conditions, which would give confusing errors if not specifically checked for:

  • If too few or too many parameters are passed in the new class(...) list, they would interact with the generated parameters for captured properties.
  • If the captured properties are added to the end of the parameter list, constructor parameters with default values would be disallowed.

Alternative 2: Automatically Calling Parent Constructor

Another possibility is that any parameters passed to the new class statement could be automatically passed to the parent constructor; so this:

# NOT supported in current proposal
$anon = new class($foo) use($bar) extends SomeOtherClass {};

would be equivalent to this:

$anon = new class($foo, $bar) extends SomeOtherClass {
    var $bar;
    public function __construct($foo, $bar) {
        $this->bar = $bar;
        parent::__construct($foo);
    }
};

This seems to avoid the need to look up and manipulate the existing constructor definition, but discovering a parent constructor is actually even more difficult, as inheritance is only resolved after compilation. That leads to a few difficulties:

  • It would be possible for the parent class to have a constructor with an incompatible signature, or no constructor at all
  • The above example uses the input $foo to name the constructor parameter, but this could be any expression, e.g. $anon = new class(42 + some_function()) use ($bar) extends SomeOtherClass {};. As such, the parameters would actually have to use generated names of some sort.

Again, this leads to new error conditions which may be hard to understand to a user who doesn't know the details of the implementation.

It would also not be very consistent with the rest of the language, which neither generates nor requires calls to parent constructors.

Alternative 3: Generating a Different Method

Similar to the workaround above, the logic for setting captured property values could be generated in a method other than the constructor, e.g. __capture.

That is, compile $anon = new class use ($foo) {}; to this:

$anon = new class {
    var $foo;
    public function __capture($foo) {
        $this->foo = $foo;
    }
};
$anon->__capture($foo);

That would allow this:

# NOT supported in current proposal
$anon = new class($b, $c) use($a) extends SomeOtherClass {
    public function __construct($b, $c) {
        do_something($b);
        parent::__construct($c);
    }
};

To be equivalent to this:

$anon = new class($b, $c) extends SomeOtherClass {
    var $a;
    public function __construct($b, $c) {
        do_something($b);
        parent::__construct($c);
    }
    public function __capture($a) {
        $this->a = $a;
    }
};
$anon->__capture($a);

The main complexity here is generating the additional method call - in the above example, it is shown as called on the local variable $anon, but in practice, it could happen anywhere in an expression, e.g. some_function(new class($a) use($b) { ... });.

Alternative 3b: Initialising Before the Constructor Call

A variation on the above would be to inject the extra method call (or the assignments themselves) immediately before the constructor is called.

Although it would give slightly nicer semantics, this would likely be even more challenging to implement, since the object creation and constructor call are both part of the NEW opcode handler, so the additional logic would need to be added there, or in variant with a new opcode.

Alternative 4: Calling an Additional Magic Method

Another variation would be to have the constructor generated as in the current implementation, but call out to another magic method for the user to define additional constructor behaviour, effectively:

public function __construct($foo) {
    $this->foo = $foo;
    if ( method_exists($this, '__afterConstruct') ) {
        $this->__afterConstruct();
    }
}

If arguments are not supported, the advantage of this over existing workarounds is very slight. If they are supported, it would run into many of the same difficulties outlined in previous sections.

Backward Incompatible Changes

None. The new syntax is not currently valid PHP, and the behaviour of existing anonymous class declarations is unchanged.

Proposed PHP Version(s)

Next PHP 8.x (hopefully 8.3)

RFC Impact

To Existing Extensions

Extensions manipulating the AST may encounter the new node kinds ZEND_AST_PROP_CAPTURE_LIST and ZEND_AST_PROP_CAPTURE, representing the list of properties and constructor parameters which are generated in the compiler.

To Opcache

None anticipated, but expert review on this point would be welcomed.

Unaffected Functionality

All existing features of anonymous classes are retained, and can be combined with the new use clause, apart from the restrictions mentioned above. That includes:

  • Inheriting parent classes
  • Implementing interfaces
  • Using traits
  • Implementing any method other than __construct
  • Declaring the entire class readonly

Future Scope

Arbitrary Expressions

When a renamed property is indicated with the $variable as $property syntax, there is no technical need to name a local variable, rather than an arbitrary expression. In other words, it would be possible to allow this:

$anon = new class use (self::ID as $id, get_some_value() * 2 as private $something) {};

Which would be equivalent to this:

$anon = new class(self::ID, get_some_value() * 2) {
    public function __construct(
        public $id,
        private $something
    ) {}
}

Extension to Anonymous Functions

Taking the above a step further, the use clause on anonymous functions could be extended in the same way, producing locally-scoped variables based on the captured values:

$callback = function() use (self::ID as $id, get_some_value() * 2 as $something) {
    do_something($id, $something);
};

Proposed Voting Choices

Add property capture to anonymous classes, with the syntax and semantics proposed, in PHP 8.3 (Yes / No, two-thirds majority required for acceptance)

Patches and Tests

Implementation

After the project is implemented, this section should contain

  1. the version(s) it was merged into
  2. a link to the git commit(s)
  3. a link to the PHP manual entry for the feature
  4. a link to the language specification section (if any)

References

Links to external references, discussions or RFCs

Rejected Features

rfc/property-capture.txt · Last modified: by 127.0.0.1

?
什么是比特币 五行缺金有什么影响 nerf是什么意思 什么东西软化鱼刺最快 尿隐血阴性是什么意思
益生菌不能和什么一起吃 黄体生成素高是什么原因 nt什么时候做 什么食物含维生素k最多 眼睛总是流泪是什么原因
子宫内膜增厚是什么意思 屋上土是什么意思 刺身是什么 c是什么车 减肥期间吃什么水果好
腹黑什么意思 血钙是什么意思 ige是什么 注意是什么意思 yq是什么意思
肠绞痛吃什么药hcv8jop9ns3r.cn 龟头是什么意思hcv8jop6ns2r.cn b族维生素什么时候吃效果最好naasee.com 青蛇是什么蛇hcv8jop5ns1r.cn 败血症是什么hcv8jop4ns9r.cn
情绪高涨是什么意思hcv9jop0ns4r.cn 八十岁是什么寿hcv7jop5ns5r.cn 天蝎座女和什么星座最配hcv8jop2ns2r.cn 莎莎舞是什么意思hcv9jop3ns1r.cn 梦见死人是什么兆头clwhiglsz.com
mo是什么元素hcv9jop6ns7r.cn 前列腺炎吃什么食物好hcv7jop4ns5r.cn 熊猫尾巴什么颜色hcv8jop4ns7r.cn 梦见水里有蛇是什么意思hcv8jop4ns8r.cn 乳腺结节是什么原因引起的hcv8jop2ns9r.cn
经常吃杏仁有什么好处hcv8jop9ns4r.cn 阿昔洛韦乳膏治什么病hcv9jop1ns4r.cn 短杆菌是什么意思hcv8jop1ns8r.cn 中性粒细胞绝对值高是什么原因hcv8jop0ns8r.cn 五四运动的精神是什么hcv9jop4ns7r.cn
百度