如何解决迁移到 PHP 8.0:使用 $this 时解除绑定 $this
我正在逐步将我的项目从 PHP 7.1 迁移到 PHP 8.0。
在官方 PHP 手册中,在 “Migrating from PHP 7.3.x to PHP 7.4.x”一章的子章节 “Deprecated Features” 中,我尝试了解以下deprecation description:
使用 $this
时解除绑定 $this
不推荐使用 $this
的非静态闭包解除绑定 $this
。
虽然没有成功。
这就是为什么我会很感激,如果有人能详细解释我,这意味着什么。也许代码片段也有帮助。
非常感谢您的时间!
也许这也有助于解释:
在我的项目中,我认为此弃用通知仅适用于一种情况:适用于下面介绍的 executeGroupHandler
类的方法 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'],]);
});
//...
解决方法
弃用是 proposed (and accepted) in this RFC,它提供了有关弃用内容及其原因的更多详细信息。
最后一句解释了哪些关闭受到影响:
特别是这适用于在非静态方法中声明的非静态闭包。首先可以通过将闭包标记为静态来避免 $this
绑定。
后来进一步缩小了 in this commit,因此它仅适用于闭包中实际提到 $this
的闭包。
与此同时,第一句话更清楚地说明了什么被弃用:
目前,可以使用 $closure->bindTo(null)
将 $this 变量与最初有一个闭包的闭包解除绑定。
关键字是unbind 而不是rebind,以及示例中的null
。
尼基塔 in this comment 还有一些背景知识:
我们对这种弃用感兴趣的原因完全是为了在 PHP 8 中启用与 $this 访问相关的一些性能改进,这是通过删除对非静态方法的静态调用来实现的。 $this 访问可以分为两类:那些我们知道 $this 是非空的和那些我们不知道的。方法调用(将)属于前一类。由于此弃用,闭包也将属于前一类。
换句话说,在 PHP 8 中,引擎会盲目地假设闭包中对 $this
的任何引用实际上都是一个对象,而不是 null。
因此,不推荐使用的特定场景是您有一个提到 $this
的闭包,然后您将它解除绑定,这样 $this
就不会设置为任何内容全部。只要您为 $this
提供新值,您就应该不受影响,因为 $this
永远不会是 null
。
很好的问题,我也不明白 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 下也可以安全运行。但我会进一步调查这个问题。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。