一步一步地将我的项目从PHP7.1迁移到PHP8.0。
在正式的PHP手册中,在“从PHP7.3.x迁移到PHP7.4.x”一章的“弃用特性”一章中,我试图理解以下贬义描述
当使用
$this$this时,取消绑定的 对于使用$this的非静态闭包,取消绑定$this是不可取的.
不过,没有成功。
这就是为什么我会感激,如果有人能详细解释我,这意味着什么。也许一个代码片段也会有帮助。
非常感谢您的时间!
也许这也有助于解释
在我的项目中,我只有一种情况,在我看来,这个不推荐的通知是可以应用的:下面所示的RouteCollection类的方法RouteCollection。我更喜欢粘贴类的更多代码,以帮助您理解我使用executeGroupHandler方法的上下文。
RouteCollection类:
<?php
namespace Packages\Router;
//...
use Packages\Router\RouteCollectionInterface;
/**
* Route collection.
*/
class RouteCollection implements RouteCollectionInterface {
//...
/**
* Group patterns list. Indexed array.
*
* Each time a group handler is executed its pattern is saved in this list.
* All addRoute operations taken place inside the scope of a group handler
* prefix the pattern of the corresponding route with the saved group pattern.
*
* @var array
*/
private $groupPatterns = [];
//...
/**
* Add a group (helper method).
*
* @param string $pattern Group pattern.
* @param \Closure $handler Group handler.
* @return $this
*/
public function group(string $pattern, \Closure $handler) {
$this->addGroup($pattern, $handler);
return $this;
}
/**
* Add a group.
*
* @param string $pattern Group pattern.
* @param \Closure $handler Group handler.
* @return $this
*/
private function addGroup(string $pattern, \Closure $handler) {
$this->saveGroupPattern($pattern);
$this->executeGroupHandler($handler);
/*
* Remove the last group pattern from the group patterns list. This step
* is performed only after all calls for adding groups/routes inside the
* scope of the current group handler have finished their processing.
*/
$this->popLastGroupPattern();
return $this;
}
/**
* Save a group pattern.
*
* @param string $pattern Group pattern.
* @return $this
*/
private function saveGroupPattern(string $pattern) {
$this->groupPatterns[] = $pattern;
return $this;
}
/**
* Execute a group handler.
*
* Temporarily bind the group handler to the route collection
* object - defined by the argument in Closure::call - and
* execute it. Inside the scope of the group handler, the route
* collection will be accessed using the keyword "$this".
*
* @link https://www.php.net/manual/en/closure.call.php Closure::call
*
* @param \Closure $handler Group handler.
* @return mixed The return value of calling the handler.
*/
private function executeGroupHandler(\Closure $handler) {
return $handler->call($this);
}
/**
* Pop the group pattern off the end of group patterns list.
*
* @return string The popped group pattern.
*/
private function popLastGroupPattern() {
return array_pop($this->groupPatterns);
}
}使用RouteCollection类:
定义了RouteCollection类后,我使用它类似于以下内容:
<?php
use Packages\Router\RouteCollection;
use SampleMvc\App\View\Template\Users\AddUser as AddUserView;
use SampleMvc\App\Controller\Users\AddUser as AddUserController;
$routeCollection = new RouteCollection();
// Add a group of routes to the route collection.
$routeCollection->group('/users/add', function() {
$this->get('', [AddUserView::class, 'index']);
$this->post('', [
'controller' => AddUserController::class,
'view' => [AddUserView::class, 'addUser'],
]);
});
//...发布于 2021-02-03 17:41:46
反对的是在本RFC中提议(并接受),它给出了关于什么是不推荐的以及为什么不推荐的更多细节。
最后一句解释了哪些闭包受到影响:
特别是,这适用于在非静态方法中声明的非静态闭包。首先,可以通过将闭包标记为静态来避免
$this绑定。
后来进一步缩小了在这个承诺中的范围,因此它只适用于闭包中实际上提到了$this的闭包。
与此同时,第一句给出了一个更清楚的例子,说明了所反对的是什么:
目前,可以通过使用$this从原来有一个闭包的闭包中解除
$closure->bindTo(null)变量的绑定。
关键字是取消绑定的而不是重新绑定的,以及示例中的null。
尼基塔在本评论中有更多的背景
我们之所以对这种弃用感兴趣,完全是为了支持PHP8中与$this访问相关的一些性能改进,这是通过删除对非静态方法的静态调用来实现的。$this访问可以分为两类:已知$this为非空的访问和不为空的访问。方法调用(will)属于前一类。这样,闭包也将归入前一类。
换句话说,在PHP8中,引擎会盲目地假设闭包中对$this的任何引用实际上都是一个对象,而不是null。
因此,不推荐的特定场景是有一个闭包提到了$this,然后您解除了它的绑定,这样$this就不会被设置为任何东西。只要您为$this提供了一个新的值,您就应该不受影响,因为$this永远不是null。
发布于 2021-02-03 17:24:20
好的问题,我也不明白PHP中“闭包的非绑定变量”意味着什么。
我编写了一个简单的测试来检查绑定另一个$this是否可以被认为是“取消绑定的$this":
class ClosureTest extends TestCase
{
private $x = 1;
public function testClosure(): void
{
var_dump(\PHP_VERSION);
$callable = function (): int {
return $this->x;
};
self::assertSame(1, \call_user_func($callable));
$closure = \Closure::fromCallable($callable);
$obj = new class {
private $x = 2;
};
self::assertSame(2, $closure->call($obj));
}
}我在7.3和8.0下运行了它,没有收到任何通知,所以您的代码也可能在8.0下运行是安全的。但我会进一步调查这个问题。
https://stackoverflow.com/questions/66031512
复制相似问题