首頁  >  文章  >  後端開發  >  PHP7類型提示:身為PHP開發者應該永遠銘記

PHP7類型提示:身為PHP開發者應該永遠銘記

藏色散人
藏色散人轉載
2020-11-01 16:46:272358瀏覽

推薦教學:《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的命令列模式來執行本文的每個範例。

PHP型別宣告

PHP7引進了兩個適當型別:標量型別和傳回值型別。我在這不會解釋它們的差異以及如何去使用它們。 PHP意見徵求稿會比我做得更好:

*https://wiki.php.net/rfc/scalar_type_hints_v5

*https://wiki.php.net/rfc /return_types

PHP7有強型別...還是很奇怪?

直截了當: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習慣弱型別。

我不願意。

事實上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模型不存在,应用的执行将会终止。

那时你仅需要去处理这个错误。简单、清晰、高效,毋庸置疑。

PHP中nullable类型和接口

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中文網其他相關文章!

陳述:
本文轉載於:luyuqiang。如有侵權,請聯絡admin@php.cn刪除