Dieser RFC empfiehlt das Hinzufügen von 4 neuen Skalartypdeklarationen: int, float, string und bool. Diese Typdeklarationen sind mit den ursprünglichen PHP-Deklarationen identisch . Der Mechanismus sorgt für eine konsistente Nutzung. Der RFC empfiehlt außerdem, jeder PHP-Datei eine neue optionale Anweisung (declare(strict_type=1);) hinzuzufügen, damit alle Funktionsaufrufe und Anweisungsrückgaben in derselben PHP-Datei eine „strikt eingeschränkte“ Anweisungsprüfung haben. Darüber hinaus wird nach dem Aktivieren strenger Typbeschränkungen beim Aufrufen von Erweiterungen oder integrierten PHP-Funktionen ein Fehler der Ebene E_RECOVERABLE_ERROR generiert, wenn die Parameteranalyse fehlschlägt. Mit diesen beiden Funktionen hofft der RFC, dass das Schreiben von PHP genauer und dokumentierter wird.
Empfohlenes Tutorial: „PHP-Tutorial“
Skalare Typdeklaration:
Keine neuen reservierten Wörter hinzugefügt. Int, Float, String und Bool werden als Typdeklarationen erkannt und dürfen nicht als Namen für Klassen/Schnittstellen/Eigenschaften usw. verwendet werden. Neue Skalartypdeklaration für Benutzer, implementiert über die interne Fast Parameter Parsing API.
strict_types/declare()-Direktive
Standardmäßig befinden sich alle PHP-Dateien im schwachen Typprüfungsmodus. Die neue Declare-Direktive gibt den Wert von strict_types an (1 oder 0). 1 gibt den strikten Typprüfungsmodus an, der für Funktionsaufrufe und Rückgabeanweisungen gilt.
declare(strict_types=1) muss die erste Anweisung der Datei sein. Wenn diese Anweisung an anderer Stelle in der Datei vorkommt, wird ein Kompilierungsfehler generiert und der Blockmodus wird ausdrücklich verboten.
Ähnlich wie die Encoding-Direktive, aber anders als die Ticks-Direktive, wirkt sich die strict_types-Direktive nur auf die angegebene Datei aus und hat keinen Einfluss auf andere darin enthaltene Dateien (durch include usw.). Diese Direktive wird zur Laufzeit kompiliert und kann nicht geändert werden. Die Funktionsweise besteht darin, ein Flag im Opcode zu setzen, damit Funktionsaufrufe und Rückgabetypprüfungen den Typbeschränkungen entsprechen.
Parametertypdeklaration
Diese Anweisung betrifft alle Funktionsaufrufe, zum Beispiel (strenger Verifizierungsmodus):
<?php declare(strict_types=1); foo(); // strictly type-checked function call function foobar() { foo(); // strictly type-checked function call } class baz { function foobar() { foo(); // strictly type-checked function call } }
Kontrast (schwacher Verifizierungsmodus)
<?php foo(); // weakly type-checked function call function foobar() { foo(); // weakly type-checked function call } class baz { function foobar() { foo(); // weakly type-checked function call } }
Rückgabetypdeklaration: Die
-Direktive wirkt sich auf die Rückgabetypen aller Funktionen in derselben Datei aus. Zum Beispiel (strenger Überprüfungsmodus):
<?php declare(strict_types=1); function foobar(): int { return 1.0; // strictly type-checked return } class baz { function foobar(): int { return 1.0; // strictly type-checked return } }
<?php function foobar(): int { return 1.0; // weakly type-checked return } class baz { function foobar(): int { return 1.0; // weakly type-checked return } }
Schwaches Verhalten bei der Typprüfung:
Ein Aufruf einer schwachen Typprüfungsfunktion, der mit PHP-Versionen vor PHP7 konsistent ist (einschließlich Erweiterungen und integrierten PHP-Funktionen). Im Allgemeinen sind die Regeln für die schwache Typprüfung für neue Skalartypdeklarationen dieselben, die einzige Ausnahme ist jedoch die Behandlung von NULL. Um mit unseren bestehenden Klassen-, Aufruf- und Array-Typdeklarationen konsistent zu sein, ist NULL nicht die Standardeinstellung, es sei denn, es wird als Parameter übergeben und NULL explizit zugewiesen.
Um eine kurze Zusammenfassung für Leser bereitzustellen, die mit den bestehenden PHP-Regeln für schwache Skalarparametertypen nicht vertraut sind. Die Tabelle zeigt die Skalartypdeklarationen, die verschiedene Typen akzeptieren und konvertieren können. NULL, Arrays und Ressourcen können keine Skalartypdeklarationen akzeptieren und sind daher nicht in der Tabelle enthalten.
* Es werden nur Nicht-NaN-Float-Typen im Bereich PHP_INT_MIN und PHP_INT_MAX akzeptiert. (Neu in PHP7, siehe ZPP-Fehler bei Überlauf-RFC)
?Nicht-numerische Zeichenfolgen werden nicht akzeptiert. Numerische Zeichenfolgen, die auf Zeichenfolgen folgen, können ebenfalls akzeptiert werden, es wird jedoch eine Benachrichtigung generiert.
?Nur wenn es die Methode __toString hat.
Strenges Typprüfungsverhalten:
Eine strikte Typprüfung beim Aufruf von Erweiterungen oder in PHP integrierten Funktionen ändert das Verhalten von zend_parse_parameters. Beachten Sie insbesondere, dass bei einem Fehler E_RECOVERABLE_ERROR anstelle von E_WARNING generiert wird. Es folgt strengen Typprüfungsregeln anstelle herkömmlicher schwacher Typprüfungsregeln. Die Regeln der strengen Typprüfung sind sehr einfach: Nur wenn der Typ mit der angegebenen Typdeklaration übereinstimmt, wird er akzeptiert, andernfalls wird er abgelehnt.
Eine Ausnahme besteht darin, dass die breite Typkonvertierung die Änderung von int in float ermöglicht. Das heißt, wenn der Parameter als Float-Typ deklariert ist, kann er weiterhin int-Parameter akzeptieren.
<?php declare(strict_types=1); function add(float $a, float $b): float { return $a + $b; } add(1, 2); // float(3)
In diesem Szenario übergeben wir einen int-Parameter an die Funktion, die so definiert ist, dass sie Float akzeptiert, und dieser Parameter wird in Float konvertiert. Andere Konvertierungen sind nicht zulässig.
Lassen Sie uns eine Funktion zum Addieren von 2 Zahlen erstellen.
add.php
<?php function add(int $a, int $b): int { return $a + $b; }
Wenn in einer separaten Datei, können wir die Add-Funktion aufrufen, indem wir schwach eingeben
<?php require "add.php"; var_dump(add(1, 2)); // int(3) // floats are truncated by default var_dump(add(1.5, 2.5)); // int(3) //strings convert if there's a number part var_dump(add("1", "2")); // int(3)
Standardmäßig ermöglicht die schwache Typdeklaration die Verwendung der Konvertierung Der übergebene Wert wird konvertiert.
<?php require "add.php"; var_dump(add("1 foo", "2")); // int(3) // Notice: A non well formed numeric value encountered
Nach dem Aktivieren der strengen Typprüfung über die optionale Declare-Direktive schlägt derselbe Aufruf in diesem Szenario jedoch fehl. Die
<?php declare(strict_types=1); require "add.php"; var_dump(add(1, 2)); // int(3) var_dump(add(1.5, 2.5)); // int(3) // Catchable fatal error: Argument 1 passed to add() must be of the type integer, float given
-Direktive wirkt sich auf alle Funktionsaufrufe in derselben Datei aus. Unabhängig davon, ob die aufgerufene Funktion in dieser Datei definiert ist, wird der strikte Typprüfungsmodus verwendet.
<?php declare(strict_types=1); $foo = substr(52, 1); // Catchable fatal error: substr() expects parameter 1 to be string, integer given
Skalare Typdeklarationen können auch zur strikten Typprüfung von Rückgabewerten verwendet werden:
<?php function foobar(): int { return 1.0; } var_dump(foobar()); // int(1)
在弱类型模式下,float被转为integer。
<?php declare(strict_types=1); function foobar(): int { return 1.0; } var_dump(foobar()); // Catchable fatal error: Return value of foobar() must be of the type integer, float returned
历史
PHP从PHP5.0开始已经有对支持class和interface参数类型声明,PHP5.1支持array以及PHP5.4支持callable。这些类型声明让PHP在执行的时候传入正确的参数,让函数签名具有更多的信息。
先前曾经想添加标量类型声明,例如Scalar Type Hints with Casts RFC,因为各种原因失败了:
(1)类型转换和校验机制,对于拓展和PHP内置函数不匹配。
(2)它遵循一个弱类型方法。
(3)它的“严格”弱类型修改尝试,既没有满足严格类型的粉丝期望,也没有满足弱类型的粉丝。
这个RFC尝试解决全部问题。
弱类型和强类型
在现代编程语言的实际应用中,有三种主要的方法去检查参数和返回值的类型:
(1)全严格类型检查(也就是不会有类型转换发生)。例如F#、GO、Haskell、Rust和Facebook的Hack的用法。
(2)广泛原始类型检查(“安全”的类型转换会发生)。例如Java、D和Pascal。他们允许广泛原始类型转换(隐式转换),也就是说,一个8-bit的integer可以根据函数参数需要,被隐形转换为一个16-bit的integer,而且int也可以被转换为float的浮点数。其他类型的隐式转换则不被允许。
(3)弱类型检查(允许所有类型转换,可能会引起警告),它被有限制地使用在C、C#、C++和Visual Basic中。它们尝试尽可能“不失败”,完成一次转换。
PHP在zend_parse_parameters的标量内部处理机制是采用了弱类型模式。PHP的对象处理机制采用了广泛类型检查方式,并不追求精确匹配和转换。
每个方法各有其优缺点。
这个提案中,默认采用弱类型校验机制,同时追加一个开关,允许转换为广泛类型校验机制(也就是严格类型校验机制)。
为什么两者都支持?
目前为止,大部分的标量类型声明的拥护者都要求同时支持严格类型校验和弱类型校验,并非仅仅支持其中一种。这份RFC,使得弱类型校验为默认行为,同时,添加一个可选的指令来使用严格类型校验(同一个文件中)。在这个选择的背后,有很多个原因。
PHP社区很大一部分人看起来很喜欢全静态类型。但是,添加严格类型校验的标量类型声明将会引起一些问题:
(1)引起明显的不一致性:拓展和PHP内置函数对标量类型参数使用弱类型校验,但是,用户的PHP函数将会使用严格类型校验。
(2)相当一部分人更喜欢弱类型校验,并不赞同这个提案,他们可能会阻止它的实施。
(3)已经存在的代码使用了PHP的弱类型,它会受到影响。如果要求函数添加标量类型声明到参数上,对于现有的代码库,这将大大增加复杂性,特别是对于库文件。
这里仍然有相当于一部分人是喜欢弱类型校验的,但是,添加严格类型校验声明和添加弱类型校验声明都会引起一些问题:
(1)大部分倾向于严格类型校验的人将不会喜欢这个提案,然后阻止它的实施。
(2)限制静态解析的机会。(可能是说,优化的机会)
(3)它会隐藏一些在类型自动转换中数据丢失的bug。
第三种方案被提出来了,就是添加区分弱类型和严格类型声明的语法。它也会带来一些问题:
(1)不喜欢弱类型和严格类型校验的人,会被强迫分别处理被定义为严格类型或者弱类型校验的库。
(2)像添加严格声明一样,这个也将和原来弱类型实现的拓展和PHP内置函数无法保持一致。
为了解决这三种方案带来的问题,这个RFC提出了第四种方案:每个文件各自定义严格或者弱类型校验。它带来了以下好处:
(1)人们可以选择适合他们的类型校验,也就是说,这个方案希望同时满足严格和弱类型校验两个阵营。
(2)API不会被强制适应某个类型声明模式。
(3)因为文件默认使用弱类型校验方案,已经存在的代码库,可以在不破坏代码结构的情况下,添加标量类型声明。也可以让代码库逐步添加类型声明,或者仅部分模块添加。
(4)只需要一个单一语法,就可以定义标量类型声明。
(5)更喜欢严格类型校验的人,通常,不仅将这个特性使用在用户定义的函数,同时也使用在拓展和PHP内置函数中。也就是说,PHP使用者会得到一个统一机制,而不会产生严格标量声明的矛盾。
(6) Im strikten Typprüfungsmodus stimmt die Fehlerstufe der durch Erweiterungen und in PHP integrierten Funktionen generierten Typüberprüfungsfehler mit der durch benutzerdefinierte Funktionen generierten Fehlerstufe überein, die beide E_RECOVERABLE_ERROR sind.
(7) Es ermöglicht die nahtlose Integration von streng typisiertem und schwach typisiertem Code in eine einzige Codebasis.
Das obige ist der detaillierte Inhalt vonDetaillierte RFC-Erklärung zur PHP7-Skalartypdeklaration. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!