ประเภทที่เข้มงวดทำอะไรใน PHP?


149

ฉันเคยเห็นบรรทัดใหม่ต่อไปนี้ใน PHP 7 แต่ไม่มีใครอธิบายว่ามันหมายถึงอะไร ฉันได้ใช้งานแล้วและทั้งหมดที่พวกเขาพูดถึงคือคุณจะเปิดใช้งานหรือไม่เหมือนกับการสำรวจความคิดเห็น

declare(strict_types = 1);

มันทำอะไร? มีผลต่อรหัสของฉันอย่างไร ควรทำหรือไม่

คำอธิบายบางอย่างจะดี



5
ลองดูที่php.net/manual/en/… สำหรับคำสั่งที่
เข้มงวด _types

คำตอบ:


154

จาก บล็อก Treehouse :

ด้วย PHP 7 ตอนนี้เราได้เพิ่มประเภท Scalar โดยเฉพาะ: int, float, string และ bool

ด้วยการเพิ่มคำแนะนำประเภทสเกลาร์และเปิดใช้ข้อกำหนดที่เข้มงวดหวังว่าจะสามารถเขียนโปรแกรม PHP ที่ถูกต้องและจัดทำเป็นเอกสารได้มากขึ้น นอกจากนี้ยังช่วยให้คุณสามารถควบคุมรหัสของคุณได้มากขึ้นและทำให้อ่านรหัสได้ง่ายขึ้น

โดยค่าเริ่มต้นการประกาศประเภทสเกลาร์ไม่เข้มงวดซึ่งหมายความว่าพวกเขาจะพยายามเปลี่ยนประเภทดั้งเดิมให้ตรงกับประเภทที่ระบุโดยการประกาศประเภท กล่าวอีกนัยหนึ่งคือถ้าคุณส่งสตริงที่ขึ้นต้นด้วยตัวเลขไปยังฟังก์ชันที่ต้องใช้ทศนิยมมันจะจับตัวเลขตั้งแต่ต้นและลบทุกอย่างออก การส่ง float เข้าไปในฟังก์ชันที่ต้องใช้ int จะกลายเป็น int (1)

ตามค่าเริ่มต้น PHP จะร่ายค่าของประเภทที่ไม่ถูกต้องเป็นประเภทสเกลาร์ที่คาดไว้ถ้าเป็นไปได้ ตัวอย่างเช่นฟังก์ชันที่กำหนดให้เป็นจำนวนเต็มสำหรับพารามิเตอร์ที่คาดว่าสตริงจะได้รับตัวแปรชนิดสตริง

ประเภทที่เข้มงวดถูกปิดใช้งาน ( eval ):

<?php

  function AddIntAndFloat(int $a, float $b) : int
  {
      return $a + $b;
  }

  echo AddIntAndFloat(1.4, '2');
  /*
  * without strict typing, PHP will change float(1.4) to int(1)
  * and string('2') to float(2.0) and returns int(3)
  */

เป็นไปได้ที่จะเปิดใช้งานโหมดเข้มงวดแบบต่อไฟล์ ในโหมดเข้มงวดระบบจะยอมรับเฉพาะตัวแปรประเภทที่แน่นอนของการประกาศประเภทเท่านั้นมิฉะนั้น TypeError จะถูกโยนออกไป ข้อยกเว้นเพียงประการเดียวสำหรับกฎนี้คือจำนวนเต็มอาจถูกกำหนดให้กับฟังก์ชันที่คาดว่าจะมีค่าลอย การเรียกใช้ฟังก์ชันจากภายในฟังก์ชันภายในจะไม่ได้รับผลกระทบจากการประกาศเข้มงวด _types

ในการเปิดใช้งานโหมดเข้มงวดคำสั่งประกาศจะใช้กับการประกาศอย่างเข้มงวด:

เปิดใช้งานประเภทที่เข้มงวดแล้ว ( eval ):

<?php declare(strict_types=1);

  function AddIntAndFloat(int $a, float $b): int
  {
      return (string) $a + $b;
  }

  echo AddIntAndFloat(1.4,'2');
  // Fatal error: Uncaught TypeError: Argument 1 passed to AddIntAndFloat() must be of the type int, float given
  echo AddIntAndFloat(1,'2');
  // Fatal error: Uncaught TypeError: Argument 2 passed to AddIntAndFloat() must be of the type float, string given

  // Integers can be passed as float-points :
  echo AddIntAndFloat(1,1);
  // Fatal error: Uncaught TypeError: Return value of AddIntAndFloat() must be of the type integer, string returned

ตัวอย่างการทำงาน:

<?php

declare(strict_types=1);

function AddFloats(float $a, float $b) : float
{
    return $a+$b;
}

$float = AddFloats(1.5,2.0); // Returns 3.5

function AddFloatsReturnInt(float $a, float $b) : int
{
    return (int) $a+$b;
}

$int = AddFloatsReturnInt($float,1.5); // Returns 5

function Say(string $message): void // As in PHP 7.2
{
    echo $message;
}

Say('Hello, World!'); // Prints "Hello, World!"

function ArrayToStdClass(array $array): stdClass
{
    return (object) $array;
}

$object = ArrayToStdClass(['name' => 'azjezz','age' => 100]); // returns an stdClass

function StdClassToArray(stdClass $object): array
{
    return (array) $object;
}

$array = StdClassToArray($object); // Returns array

function ArrayToObject(array $array): object // As of PHP 7.2
{
    return new ArrayObject($array);
}

function ObjectToArray(ArrayObject $object): array
{
    return $object->getArrayCopy();
}

var_dump( ObjectToArray( ArrayToObject( [1 => 'a' ] ) ) ); // array(1 => 'a');

3
ข้อผิดพลาดร้ายแรงแรกที่กล่าวถึงในตัวอย่างที่เปิดใช้งานประเภทที่เข้มงวดของคุณไม่ถูกต้อง ดังที่ได้กล่าวไว้ในเอกสารประกอบ: "ข้อยกเว้นเพียงประการเดียวสำหรับกฎนี้คือจำนวนเต็มอาจถูกกำหนดให้กับฟังก์ชันที่คาดว่าจะมีค่าทศนิยม" การเรียกใช้ฟังก์ชันจะไม่ล้มเหลวใน int มันจะอยู่บนสตริงแม้ว่า
พอล

63

strict_types มีผลต่อการบังคับประเภท

การใช้คำแนะนำประเภทโดยไม่strict_typesอาจนำไปสู่ข้อบกพร่องที่ละเอียดอ่อน

ก่อนประเภทที่เข้มงวดint $xหมายความว่า " $xต้องมีค่าบังคับให้เป็น int" ค่าใด ๆ ที่สามารถบังคับให้เป็นได้intจะส่งผ่านคำใบ้ประเภท ได้แก่ :

  • int ที่เหมาะสม (242 )
  • ลอย (10.17 )
  • บูล (true ),
  • null, หรือ
  • สตริงที่มีตัวเลขนำหน้า ( "13 Ghosts")

โดยการตั้งค่าstrict_types=1คุณจะบอกเครื่องยนต์ว่าint $x"$ x ต้องเป็น int ที่เหมาะสมเท่านั้นไม่อนุญาตให้มีการบังคับประเภทใด" คุณมีความมั่นใจอย่างมากว่าคุณจะได้รับสิ่งที่ได้รับเท่านั้นโดยไม่มีการแปลงและการสูญเสียที่อาจเกิดขึ้น

ตัวอย่าง:

<?php
function get_quantity(): int {
    return '100 apples';
}
echo get_quantity() . PHP_EOL;

ให้ผลลัพธ์ที่อาจสับสน:

Notice: A non well formed numeric value encountered in /Users/bishop/tmp/pmkr-994/junk.php on line 4
100

ฉันคิดว่านักพัฒนาซอฟต์แวร์ส่วนใหญ่คาดหวังว่าintคำใบ้จะหมายถึง "เฉพาะ int" แต่มันไม่ได้หมายความว่า "อะไรก็ได้เช่น int" การเปิดใช้งาน tight_types ทำให้เกิดพฤติกรรมที่คาดหวังและต้องการ:

<?php declare(strict_types=1);

function get_quantity(): int {
    return '100 apples';
}
echo get_quantity() . PHP_EOL;

อัตราผลตอบแทน:

Fatal error: Uncaught TypeError: Return value of get_quantity() must be of the type int, string returned in example.php:4

ฉันคิดว่ามีสองบทเรียนที่นี่หากคุณใช้คำใบ้ประเภท:

  • ใช้ strict_types=1เสมอ
  • แปลงการแจ้งเป็นข้อยกเว้นในกรณีที่คุณลืมเพิ่มstrict_typespragma

1
นี่ได้รับคำตอบที่ดีเหมือนเกือบปีที่แล้ว;)
emix

6
อันที่จริงฉันโหวตคำตอบอื่น @emix อย่างไรก็ตามฉันรู้สึกว่าคำถามที่ว่า "ฉันควรทำ" ไม่ได้สัมผัส strict_typesฉันยังรู้สึกว่าเป็นตัวอย่างที่มีขนาดกะทัดรัดมากขึ้นและที่น่าตกใจจะส่งเสริมให้คนใช้
อธิการ

1
ฉันคิดว่าคำถามนี้ตอบอย่างรวบรัดว่า "ฉันควรทำไหม" ส่วนหนึ่งของคำถามของ OP กลับไปที่ PHP หลังจากหายไปเล็กน้อยและนี่เป็นประโยชน์มาก
Darragh Enright
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.