ホームページ  >  記事  >  バックエンド開発  >  PHP7 スカラー型宣言 RFC 詳細説明

PHP7 スカラー型宣言 RFC 詳細説明

coldplay.xixi
coldplay.xixi転載
2020-06-22 17:54:193808ブラウズ

PHP7 スカラー型宣言 RFC 詳細説明

1. 概要

この RFC では、int、float、string、bool の 4 つの新しいスカラー型宣言を追加することを推奨しています。これらの型宣言は、PHP の元の型宣言と同じになります。 . このメカニズムにより、一貫した使用が維持されます。また、RFC は、同じ PHP ファイル内のすべての関数呼び出しとステートメントの戻り値が「厳密に制約された」スカラー型を持つように、新しいオプションの命令 (declare(strict_type=1);) を各 PHP ファイルに追加することを推奨しています。さらに、厳密な型制約をオンにした後、拡張機能または PHP 組み込み関数を呼び出すと、パラメーターの解析が失敗すると E_RECOVERABLE_ERROR レベルのエラーが生成されます。これら 2 つの機能により、RFC は PHP の記述がより正確になり、文書化されることを期待しています。

推奨チュートリアル: 「PHP チュートリアル

2. 詳細

スカラー型宣言:

新しい予約語は追加されません。 Int、float、string、bool は型宣言として認識され、クラス/インターフェイス/トレイトなどの名前として使用することは禁止されます。新しいユーザー スカラー型宣言。内部高速パラメーター解析 API を通じて実装されます。

strict_types/declare() ディレクティブ

デフォルトでは、すべての PHP ファイルは弱い型チェック モードになっています。新しい宣言ディレクティブは strict_types の値 (1 または 0) を指定します。1 は厳密な型チェック モードを示し、関数呼び出しと return ステートメントに適用されます。0 は弱い型チェック モードを示します。

declare(strict_types=1) は、ファイルの最初のステートメントでなければなりません。このステートメントがファイル内の他の場所にある場合、コンパイル エラーが生成され、ブロック モードは明示的に禁止されます。

エンコーディング ディレクティブと似ていますが、ticks ディレクティブとは異なります。strict_types ディレクティブは指定されたファイルにのみ影響し、(include などを通じて)それに含まれる他のファイルには影響しません。このディレクティブは実行時にコンパイルされ、変更できません。その仕組みは、関数呼び出しと戻り値の型チェックが型制約に準拠するようにオペコードにフラグを設定することです。

パラメータ タイプ宣言

この命令はすべての関数呼び出しに影響します。たとえば (厳密検証モード):

<?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
    }
}

Contrast (弱い検証モード)

<?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
    }
}

戻り値の型宣言:

このディレクティブは、同じファイル内のすべての関数の戻り値の型に影響します。例 (厳密検証モード):

<?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
    }
}

弱い型チェックの動作:

弱い型チェック関数呼び出しは、PHP7 より前のバージョンの PHP (拡張機能および PHP 組み込み関数を含む) と一貫性があります。一般に、弱い型チェック規則は新しいスカラー型宣言でも同じですが、唯一の例外は NULL の処理です。既存のクラス、呼び出し、および配列型の宣言と一貫性を保つために、パラメーターとして渡され、明示的に NULL に割り当てられない限り、NULL はデフォルトではありません。

PHP の弱いスカラー パラメーター型に関する既存のルールに詳しくない読者に簡単な概要を提供します。この表には、さまざまな型が受け入れおよび変換できるスカラー型宣言が示されています。NULL、配列、リソースはスカラー型宣言を受け入れることができないため、これらは表には含まれていません。

*PHP_INT_MIN と PHP_INT_MAX の範囲内の非 NaN float 型のみが受け入れられます。 (PHP7 の新機能、オーバーフロー RFC の ZPP 失敗を参照)
?数値以外の文字列は受け入れられません文字列に続く数値文字列も受け入れることができますが、通知が生成されます。

?__toString メソッドがある場合のみ。

厳密な型チェックの動作:

厳密な型チェックでは、拡張機能または PHP 組み込み関数が呼び出され、zend_parse_parameters の動作が変更されます。失敗すると、E_WARNING ではなく E_RECOVERABLE_ERROR が生成されることに注意してください。従来の弱い型チェック ルールではなく、厳密な型チェック ルールに従います。厳密な型チェックのルールは非常に単純です。型が指定された型宣言と一致する場合にのみ受け入れられ、そうでない場合は拒否されます。

1 つの例外は、ワイド型変換では int を float に変更できることです。つまり、パラメーターが float 型として宣言されている場合でも、int パラメーターを受け入れることができます。

<?php
declare(strict_types=1);
 
function add(float $a, float $b): float {
    return $a + $b;
}
 
add(1, 2); // float(3)

このシナリオでは、float を受け入れるように定義された関数に int パラメーターを渡し、このパラメーターは float に変換されます。これ以外の変換は許可されません。

3. 例:

2 つの数値を加算する関数を作成してみましょう。

add.php

<?php
function add(int $a, int $b): int {
    return $a + $b;
}

別のファイルにある場合は、弱く入力することで add 関数を呼び出すことができます。

<?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)

デフォルトでは、弱い型宣言により変換の使用が許可されています。渡された値は変換されます。

<?php
require "add.php";
 
var_dump(add("1 foo", "2")); // int(3)
// Notice: A non well formed numeric value encountered

ただし、オプションの宣言ディレクティブを通じて厳密な型チェックをオンにした後、このシナリオでは同じ呼び出しは失敗します。

<?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

ディレクティブは、同じファイル内のすべての関数呼び出しに影響します。呼び出される関数がこのファイルに定義されているかどうかに関係なく、厳密な型チェック モードが使用されます。

<?php
declare(strict_types=1);
 
$foo = substr(52, 1);
// Catchable fatal error: substr() expects parameter 1 to be string, integer given

スカラー型宣言は、戻り値の厳密な型チェックにも使用できます:

<?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) 厳密な型検査モードでは、拡張機能および PHP 組み込み関数によって生成される型検証失敗のエラー レベルは、ユーザー定義関数によって生成されるエラー レベルと一致します (どちらも E_RECOVERABLE_ERROR)。

(7) 厳密に型指定されたコードと弱く型指定されたコードを単一のコード ベースにシームレスに統合できます。

以上がPHP7 スカラー型宣言 RFC 詳細説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はjuejin.imで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。