目前PHP8.2的發佈時間還沒有確定,但是預計將在2022年末發布。這篇文章將為你介紹在新版本中的功能、效能改進、棄用的特性等等。
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中文網其他相關文章!