PHP8.2將有哪些改動(效能改進、新功能)!

青灯夜游
發布: 2023-04-11 06:50:02
轉載
4111 人瀏覽過

目前PHP8.2的發佈時間還沒有確定,但是預計將在2022年末發布。這篇文章將為你介紹在新版本中的功能、效能改進、棄用的特性等等。

相關推薦:PHP8.2最新進展,即將進行新特性凍結!

null和false將作為獨立的類型

PHP並不會陷入到完美的類型安全方向中,但是從技術的角度考慮,將null和false作為獨立的資料類型是值得的。一般情況下,PHP的許多常見的函數,會透過回傳false表示出錯了。例如在file_get_content:

file_get_contents(/* … */): string|false
登入後複製

在以前,false可以在聯合型別中使用,但不能獨立使用,在PHP8.2可以單獨使用:

function alwaysFalse(): false
{
    return false;
}
登入後複製

當然,對於這個做法,有些開發者都持謹慎態度。他並不支援true作為獨立類型。這些開發者認為,false只是一個值,類型應該代表類別而不是一個值。當然在類型系統中,有一個概念是單元類型,它是只允許一個值的類型。但這真的有用嗎?

不過另一個RFC也正在討論將true作為一種類型加入PHP。

一個獨立的null卻很有意義,這樣可以簡單地實作空物件模式:

class Post
{
    public function getAuthor(): ?string { /* … */ }
}

class NullPost extends Post
{
    public function getAuthor(): null { /* … */ }
}
登入後複製

這對NullPost::getAuthor()能夠說它只會傳回null,不必像以前那樣必須將null和string一起聯合聲明。

棄用動態屬性

對於語言規範來說,這是更好的設計,但也會限制很多用法。動態屬性在PHP8.2中被棄用,並且會在PHP中拋出錯誤異常。

什麼是動態屬性?就是你沒有在類別中聲明這些屬性,但仍然可以設定和獲取:

class Post
{
    public string $title;
}

// …

$post->name = 'Name';  // 在PHP8.2中不能这样使用,因为并没有在类中声明
登入後複製

不過放心,__set和__get等魔術方法將仍然按預期工作:

class Post
{
    private array $properties = [];

    public function __set(string $name, mixed $value): void
    {
        $this->properties[$name] = $value;
    }
}

// …

$post->name = 'Name';
登入後複製

標準對象也是如此:stdClass將繼續支援動態屬性。

PHP曾經是一種動態程度很強的動態語言,但是現在已經有很多人願意接受更嚴格的程式設計方式了。盡可能的嚴格,盡可能的依賴靜態分析是件好事,這能讓開發者寫出更好的程式碼。

不過可能一部分很重視動態屬性的開發人員對這種變化會很不滿意,如果你不想在使用PHP8.2時看到這些警告,可以這樣做:

#可以使用#[AllowDynamicProperties]

#[AllowDynamicProperties]
class Post
{
    public string $title;
}

// …

$post->name = 'Name'; // 一切正常
登入後複製

另一種方法是修改警報級別,但不建議這樣做。等你打算升級到PHP9.0時會遇到麻煩。

error_reporting(E_ALL ^ E_DEPRECATED);
登入後複製

追蹤呼叫時參數脫敏

什麼叫參數脫敏?在我們開發時,遇到錯誤,都會使用Trace調試,但是目前的堆疊記錄下一些敏感數據,例如環境變數、密碼、使用者。

在PHP8.2中允許對參數進行一些編排( Redact ,姑且叫做編排,有一些修飾的意思,但直接稱為修飾並不合適),例如將一些參數設定脫敏,這樣這些參數的呼叫值不會在堆疊資訊中列出:

function test(
    $foo,
    #[\SensitiveParameter] $bar,
    $baz
) {
    throw new Exception('Error');
}

test('foo', 'bar', 'baz');
登入後複製

如果報錯的話,會發現,第二個參數bar並沒有記錄實際的值。這樣能起到脫敏的作用,如果傳的是密碼的話,就不會別記錄下來。

Fatal error: Uncaught Exception: Error in test.php:8
Stack trace:
#0 test.php(11): test('foo', Object(SensitiveParameterValue), 'baz')
#1 {main}
  thrown in test.php on line 8
登入後複製

棄用了部分物件的呼叫方式

#一些先前的呼叫物件方式杯棄用了。這裡面有些是需要透過call_user_func($callable)來呼叫的,而不是能夠$callable()直接呼叫的。

"self::method"
"parent::method"
"static::method"
["self", "method"]
["parent", "method"]
["static", "method"]
["Foo", "Bar::method"]
[new Foo, "Bar::method"]
登入後複製

為什麼要這樣做呢? Nikita在RFC討論中很好的做出了解釋:

這些廢棄的呼叫都是有關上下文的,「self::method」所指的方法取決於從哪個類別執行呼叫或可調用性檢查。實際上,當以[new Foo, "parent::method"]的形式使用時,這通常也適用於最後兩種情況。 

減少可呼叫物件的上下文相關性是本RFC的次要目標。在這個RFC之後,唯一剩下的範圍依賴是方法可見性:「Foo::bar」可能在一個範圍內可見,但在另一個範圍內不可見。如果將來可呼叫物件僅限於公共方法,那麼可呼叫類型將變得明確定義並且可以用作屬性類型。但是,對可見性處理的變更不建議作為本RFC的一部分。

提升對未定義變數的偵測機制和等級

未定義的變數是那些在被讀取之前還沒有被初始化的變數。存取未定義的變數目前會發出E_WARNING“警告:未定義的變數$varname”,並將變數視為null,但不會中斷執行,從而允許程式碼執行繼續有增無減,但可能處於意外狀態。 

目前可以透過一些配置,讓PHP執行時對未定義變數產生錯誤級異常,但這需要單獨配置。 PHP應預設提供更安全的檢驗。

一般什么情况下会出现未定义变量的情况呢?

用法1

变量在某个分支中声明,比如在if中设置一个值。

if  ( $user -> admin )  {
   $restricted  =  false ;
}

if  ( $restricted )  {
   die ( '你没有进入这里的权限' ) ;
}
登入後複製

用法2

变量拼写错误:

$name = 'Joe';
echo 'Welcome, ' . $naame;
登入後複製

这种用法在1中也可能会发生:

if ($user->admin) {
   $restricted = false;
} else {
   $restrictedd = true;
}

if ($restricted) {
   die('You do not have permission to be here');
}
登入後複製

用法3

在循环中定义,但这个循环可能并没有执行:

while ($item = $itr->next()) {

   $counter++; // 定义变量
}

  // 这里调用了变量,但是很有可能并没有定义这个变量
echo 'You scanned ' . $counter . ' items';
登入後複製

解决方法

在这些分支之前提前定义好一个默认值。

对于第1种用法:

$restricted = true;
if ($user->admin) {
   $restricted = false;
}

if ($restricted) {
   die('You do not have permission to be here');
}
登入後複製

对于第3种用法:

$counter = 0;
while ($item = $itr->next()) {
   $counter++;
}

echo 'You scanned ' . $counter . ' items';
登入後複製

这样做的好处是消除了整个访问和使用这些未定义变量的后果,以及回退到引擎默认状态的用户态错误。这样我们提供了另一层保护,防止PHP程序发生了这种意外后继续运行。

这种更改也会让PHP引擎和JIT等方面不会那么复杂。

这个版本主要是针对PHP9.0的,在PHP8.2的还是警告,在以后会将这种行为提升到错误级别。

增加只读类

通过给类添加只读修饰符来声明只读类。

readonly class Test {
    public string $prop;
}
登入後複製

这样做会隐式地将类的所有实例属性标记为只读。此外,它将阻止创建动态属性。

readonly class Foo
{
    public int $bar;

    public function __construct() {
        $this->bar = 1;
    }
}

$foo = new Foo();
$foo->bar = 2;
// 抛出错误,不能修改只读属性 Foo::$bar

$foo->baz = 1;
// 抛出错误:不能动态创建属性 Foo::$baz
登入後複製

可以通过增加#[AllowDynamicProperties]属性,可以不触发错误的情况下创建动态属性。

#[AllowDynamicProperties]
readonly class Foo {
}
登入後複製

一些限制:

由于是只读类,必须对属性声明类型:

readonly class Foo
{
    public $bar;
}
// 以上定义会产生错误。
登入後複製

不能使用静态属性:

readonly class Foo
{
    public static int $bar;
}
// 抛出错误: 只读属性不能声明静态类型
登入後複製

原文地址:https://phpreturn.com/index/a626a74a300dc5.html

原文平台:PHP武器库

版权声明:本文由phpreturn.com(PHP武器库官网)原创和首发,所有权利归phpreturn(PHP武器库)所有,本站允许任何形式的转载/引用文章,但必须同时注明出处。

推荐学习:《PHP视频教程

以上是PHP8.2將有哪些改動(效能改進、新功能)!的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
php
來源:phpreturn.com
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!