推奨チュートリアル: "PHP7"
この記事は http://web-techno.net/typing-with-php-7-what-you から翻訳されたものです- shouldnt -do/ 、英語が得意な方は原文へどうぞ。
PHP7 に強い型付けが登場したとき、私は光を見ました。ようやく、PHP の弱い型付けによるバグや不一致はもう発生しないと確信できました。
あるコードを読んだことを覚えていますが、そこに含まれる変数の型についてはまったくわかりませんでした。このメソッドの戻り値は int 型を使用する必要がありますか?ブール型?これにより、隠れたバグや予期せぬ動作が発生するのでしょうか?
厳密な型付けは、戻り値の型のヒントと同様に便利です。どのようなデータを扱っているかを正確に把握できます。もう推測する必要はありません。
ただし、この記事での私の取り組みは PHP7 で終わりではありません。 PHP7 はこの問題を解決するために懸命に取り組んでいますが、難読化されたコードを記述することは可能です。コードを整理しておくために従う必要のあるルールがいくつかあります。
この記事の各例を実行するには、PHP7.1.1-dev のコマンド ライン モードを使用します。
PHP7 では、スカラー型と戻り値型という 2 つの適切な型が導入されています。ここでは、それらの違いと使用方法については説明しません。 PHP コメントドラフトは私よりもうまくやるでしょう:
*https://wiki.php.net/rfc/scalar_type_hints_v5
*https://wiki.php.net/rfc /return_types
率直に言いましょう。PHP7 プログラミングでは、予期しない結果が生じる可能性があります。
これを疑いますか?以下にいくつかの例を示します。
function mySuperFunction(): int{ return "hello world"; } mySuperFunction();
このコードは問題ありません。型宣言は、このメソッドが int 型を返す必要があることを示しています。ただし、文字列型を返します。言うまでもなく、PHP はエラーをスローします:
致命的エラー: Uncaught TypeError: mySuperFunction() の戻り値は整数型、返される文字列である必要があります。 致命的なエラー: キャッチされない型エラー: mySuper 関数の戻り値の型は int 型である必要があります。文字列が返されました。
別の例を見てみましょう:
function mySuperFunction():int{ return "hello world1"; } mySuperFunction();
上と同じ結果: タイプ エラー。良い!戻り値の型が間違っているのでしょうか?私はあなたに嘘をつきましたか?
function mySuperFunction():int{ return "1hello world"; } mySuperFunction();
これは例外をスローすべきではないでしょうか?戻り値の型を int として明確に定義しましたが、返されるのは文字列です。
翻訳著者の補足: PHP7.2.4 は通知エラーをスローします:
通知: 整形式でない数値が見つかりました 不適切な形式の数値型値
エラーが発生しました。この関数は 1 を返します。
function mySuperFunction():int{ return 1.1456415; } mySuperFunction();
戻り値の int 型を定義します。明らかに、実際の戻り値の型は float です。しかし、このコードは例外をスローしません。
1 が返されます。
まだ納得できない場合は、
function mySuperFunction():bool{ return "1hello world"; } mySuperFunction();
PHP は '1hello world' をブール型として扱い、1 を返します。
function mySuperFunction():bool{ return "abcde"; } mySuperFunction();
PHP の奇妙な世界では、「abcde」はブール値です。実際、このメソッドは true を返します!
ご覧のとおり、これらのコーディング ルールは依然として混乱を引き起こします。つまり、コードが明確であっても、それが真実ではない可能性があります。
PHP は弱い型付けに慣れています。 ######したくないです。
実際、PHP は実行時に文字列型を Boolean 型と int 型に自動的に変換します。コードをめちゃくちゃにするだけです!シンプルで明確であるべきものがめちゃくちゃになっています。
はっきりさせておきましょう。私たちは開発者です。したがって、コード内のデータの種類を制御する必要があります。
そうしないと、バグへの扉が開かれ、開発者の間に奇妙な動作や誤解が広まることになります。コードが変わります。虫が現れ、上司は解雇され、妻はあなたに失望し、あなたは奈落の底に落ちるでしょう。自分を責めて悲しくて寂しい。
まだ救済のチャンスはあります!すべてのことが可能です。 PHP には解決策があります。
厳密な型モードに注意してください:
declare(strict_types=1);function mySuperFunction(): bool{ return 'abcde'; }echo mySuperFunction();
このコードを実行すると、致命的なエラーが発生します:
致命的なエラー: Uncaught TypeError: mySuperFunction() の戻り値ブール型である必要があります。文字列が返されます!キャッチされない型エラー: mySuperFunction() の戻り値はブール型である必要があり、文字列が返されます!
このエラーが画面にポップアップ表示されるのを見て、とてもうれしく思いました。通常、エラーが発生するのは好ましくありませんが、今回は問題ありませんでした。もちろん、ブール型ではなく文字列型です。
私の提案は、この厳密な型宣言をコードのすべての部分に入れることです。どこでも! IDE のコード スニペットを作成します。 PHP ファイルを作成するたびに、先頭に厳密な型宣言を置く必要があります。
残念ながら、厳密モードをグローバルに設定することはできません。すべての PHP ファイルでこれを行う必要があります。理由は簡単です。たとえ厳密に型指定されたモードを実装する必要がない場合でも、アプリケーション内のあらゆるパッケージや他の種類のリソースが対象となるからです。
同意しない人もいると思います。 「柔軟性」を実現するために、コードの一貫性を破壊しようとする人がいるのは承知しています。
「ブール型は文字列型として表現する必要があると主張するのは簡単です。」という議論はわかります。
我会回复他们:修复你的结构和/或你的实现。如果代码是弱类型,就会有一些问题。如果你确实需要,请修复真实存在的问题,不用再徘徊于把布尔值作为一个字符串或者int类型。
你是开发者。你不是黑客。你要解决问题,而不是与问题为伍。
五个字概括:强类型骄傲!PHP7是强类型类型语言了!
PHP7.1中Nullable类型 请小心nullable类型的笑里藏刀!它是猛兽!
nullabla类型详见PHP意见征求稿
你怎么会用错?
declare(strict_types=1);class User{ //Value object}class UserRepository{ private $database; public function construct(Database $database){ $this->database = $database; } public function getUserById(int $id):?User { //If user is not in the database, return null $user = $this->database->fetchUser($id); return $user; } }class EmailSender{ public function sendEmailToUser(int $userId) { $userRepository = new UserRepository(new Database()); $user = $userRepository->getUserById($userId); //Can send email to... null! $this->sendEmail($user); } } $emailSender = new EmailSender(); $emailSender->sendEmailToUser(12345);
这段代码将会崩溃,因为我们试图获取数据库中不存在的User模型。我们怎么能给null发邮件?
很明显你应该用如下方法修正:
...class EmailSender{ public function sendEmailToUser($userId) { $userRepository = new UserRepository(new Database()); $user = $userRepository->getUserById($userId); if ($user !== null) { $this->sendEmail($user); } } }
但是这个方法有两个问题:
对nullable的处理将导致判断是否为null的判断到处都是(if ($methodReturn !== null))。无用且聒噪。
如果用户不存在以上代码将会静静地失败。「为什么用户没收到邮件?」将会是你的噩梦。你需要明白:
用户模型不存在(可能是一个错误的用户id被传入了getUserByid())
用户模型为null,可能因为nullable类型
加上null的条件判断,导致应用什么都没做
这是另一种方式:
...class UserRepository{ private $database; public function construct($database){ $this->database = $database; } public function getUserById($id):User { $user = $this->database->fetchUser($id); //If user is not in the database, an error will be thrown! return $user; } } ...
在这个例子中没必要使用nullalble类型。代码将会抛出一个异常。如果User模型不存在,应用的执行将会终止。
那时你仅需要去处理这个错误。简单、清晰、高效,毋庸置疑。
nullable类型有一些其他的意外。
declare(strict_types=1);interface MySuperInterface{ public function superFunction():?int; }class SuperClass implements mySuperInterface{ public function superFunction():int { return 42; } } $superClass = new SuperClass();echo $superClass->superFunction();
Super类实现了接口MySubper,但不会实现接口约定。接口要求返回nullable的类型,实际将返回int类型。
然而,这段代码在PHP7.1中不会抛出错误。
等等。。。我们需要如接口中表示的那样无论如何都要返回null?
让我们尝试一下:
declare(strict_types=1);interface MySuperInterface{ public function superFunction():?int; }class SuperClass implements mySuperInterface{ public function superFunction():int { return null; } } $superClass = new SuperClass();echo $superClass->superFunction();
结果如下:
Fatal error: Uncaught TypeError: Return value of SuperClass::superFunction() must be of the type integer, null returned 致命错误:未捕获的类型错误:Super类的super方法的返回值必须得是int类型,返回了null
现在我应该理解了在某场景下很有用,比如不能在数据库中存null值时。
我强烈建议你谨慎使用。我很少在代码中使用这个类型,因为我通常有更好的解决办法。
我更喜欢在大多场景下使用null对象代替null。为什么?简而言之,因为我讨厌在任何时候检测变量是否为null!
我喜欢PHP。尤其当它引入了强类型。可能还不完美,但是将会越来越好。
不过当你在PHP中操作类型时,一定要多加小心。我还是要强调:
需要使用严格类型。
需要控制应用中数据。
如果仍使用弱类型,将会是个问题。因此:修复它!
不应该猜测变量的类型到底是什么。
尽可能避免使用nullable类型
为了每个使用我们的代码的开发人员,我们需要保持一致性。对我来说,意味着很专业。
很明显在留言中阅读你们的建议使我很开心。
参考:
http://web-techno.net/typing-with-php-7-what-you-shouldnt-do/
以上がPHP7 タイプのヒント: PHP 開発者として常に覚えておくべきことの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。