推薦教學:《PHP7》
本文翻譯自http://web-techno.net/typing-with-php-7-what-you-shouldnt -do/,英文好的請移步原文。
當PHP7出現了強型,我看到了光明。我終於有信心不會再因為PHP弱型別看見bug或不一致的狀況。
我記得讀過一些程式碼,對其中的變數該是的型別沒什麼想法。這個方法我該使用int型別作為回傳值? boolen類型?這樣將會產生一些隱藏的bug或不可預見的行為?
嚴格類型很有用,傳回值類型提示也很有用。你很了解你正處理的數據是什麼。你再也不用靠猜了。
但是,PHP7並不是我這篇文章努力的結束。你仍可以寫出易混淆的程式碼,即使PHP7努力去修復這個問題。你需要遵守一些規則來讓你的程式碼保持規範。
我會使用PHP7.1.1-dev的命令列模式來執行本文的每個範例。
PHP7引進了兩個適當型別:標量型別和傳回值型別。我在這不會解釋它們的差異以及如何去使用它們。 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會拋出了一個錯誤:
Fatal error: Uncaught TypeError: Return value of mySuperFunction() must be of the type integer, string returned. 致命錯誤:未捕捉的類型錯誤:mySuper函數傳回類型必須是int類型,傳回了字串。
讓我們來看另一個例子:
function mySuperFunction():int{ return "hello world1"; } mySuperFunction();
和上邊相同的結果:型別錯誤。好!回傳類型有什麼問題嗎?我沒騙到你吧?
function mySuperFunction():int{ return "1hello world"; } mySuperFunction();
這不是應該拋出例外嗎?我們很明確地定義了回傳類型為int,但傳回的卻是一個字串。
翻譯作者補充:PHP7.2.4會拋出注意型錯誤:
Notice: A non well formed numeric value encountered 出現一個不好的格式化數字類型值
錯。函數返回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會在運作時默默地把字串型別轉換成布林類型,轉換成int型別。就把你的程式碼搞混了!本該簡單明了的東西搞亂了。
讓我們明確下。我們是開發者。因此我們應該在程式碼中控制資料的類型。
如果我們不這樣,我們將打開bug之門,在開發者間傳播怪行為和誤解。代碼將會改變。 bug將會出現,老闆將會解雇了你,妻子將會對你失望,你將會墜入深淵。在自責中難過、孤獨。
還有補救的機會!所有事情都可能。 PHP有解決方法!
注意嚴格型別模式:
declare(strict_types=1);function mySuperFunction(): bool{ return 'abcde'; }echo mySuperFunction();
執行這段程式碼,你將會得到一個致命的錯誤:
Fatal error: Uncaught TypeError: Return value of mySuperFunction() must be of the type boolean, string returned!
未捕獲的類型錯誤: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中文網其他相關文章!