Apa yang dilakukan tipe ketat dalam PHP?

147

Saya telah melihat baris baru berikut di PHP 7, tetapi tidak ada yang benar-benar menjelaskan apa artinya. Saya sudah mencarinya di Google dan yang mereka bicarakan hanyalah apakah Anda akan mengaktifkannya atau tidak suka jenis polling.

declare(strict_types = 1);

Apa fungsinya? Bagaimana pengaruhnya terhadap kode saya? Haruskah saya melakukannya?

Beberapa penjelasan akan menyenangkan.

sufuko
sumber
5
. coba lihat ini juga php.net/manual/en/… untuk strict_types directive
scaisEdge

Jawaban:

153

Dari blog Treehouse :

Dengan PHP 7 kami sekarang telah menambahkan jenis Scalar. Khususnya: int, float, string, dan bool.

Dengan menambahkan petunjuk jenis skalar dan mengaktifkan persyaratan yang ketat, diharapkan program PHP yang lebih benar dan mendokumentasikan diri dapat ditulis. Ini juga memberi Anda lebih banyak kontrol atas kode Anda dan dapat membuat kode lebih mudah dibaca.

Secara default, deklarasi tipe skalar adalah non-ketat, yang berarti mereka akan berusaha untuk mengubah tipe asli agar sesuai dengan tipe yang ditentukan oleh deklarasi tipe. Dengan kata lain, jika Anda meneruskan string yang dimulai dengan angka ke fungsi yang membutuhkan float, itu akan mengambil nomor dari awal dan menghapus yang lainnya. Melewati float ke fungsi yang membutuhkan int akan menjadi int (1).

Secara default, PHP akan memberikan nilai dari tipe yang salah ke dalam tipe skalar yang diharapkan jika memungkinkan. Misalnya, fungsi yang diberi bilangan bulat untuk parameter yang mengharapkan string akan mendapatkan variabel tipe string.

Jenis ketat dinonaktifkan ( 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)
  */

Dimungkinkan untuk mengaktifkan mode ketat berdasarkan per file. Dalam mode ketat, hanya variabel tipe deklarasi tipe persis yang akan diterima, atau TypeError akan dilempar. Satu-satunya pengecualian untuk aturan ini adalah bahwa integer dapat diberikan ke fungsi yang mengharapkan float. Panggilan fungsi dari dalam fungsi internal tidak akan terpengaruh oleh deklarasi strict_types.

Untuk mengaktifkan mode ketat, pernyataan pernyataan digunakan dengan deklarasi strict_types:

Jenis ketat diaktifkan ( 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

Contoh kerja:

<?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');
Saif
sumber
3
Kesalahan fatal pertama yang disebutkan dalam contoh ketat jenis Anda yang diaktifkan salah. Seperti disebutkan dalam dokumentasi: "Satu-satunya pengecualian untuk aturan ini adalah bahwa integer dapat diberikan ke fungsi yang mengharapkan float." Panggilan fungsi tidak akan gagal di int. Akan pada string sekalipun.
Paul
63

strict_types mempengaruhi tipe paksaan.

Menggunakan petunjuk jenis tanpa strict_typesdapat menyebabkan bug halus.

Sebelum tipe yang ketat, int $xberarti " $xharus memiliki nilai yang dapat dipaksakan untuk int." Nilai apa pun yang dapat dipaksakan kepada suatu intakan melewati petunjuk tipe, termasuk:

  • int tepat ( 242),
  • float ( 10.17),
  • a bool ( true),
  • null, atau
  • string dengan digit terdepan ( "13 Ghosts").

Dengan menyetel strict_types=1, Anda memberi tahu mesin itu int $xberarti "$ x hanya boleh berupa int yang tepat, tidak ada paksaan tipe yang diizinkan." Anda memiliki jaminan besar bahwa Anda mendapatkan persis dan hanya apa yang diberikan, tanpa konversi dan potensi kerugian.

Contoh:

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

Menghasilkan hasil yang berpotensi membingungkan:

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

Kebanyakan pengembang akan mengharapkan, saya pikir, sebuah intpetunjuk yang berarti "hanya sebuah int". Tetapi tidak, itu berarti "sesuatu seperti int". Mengaktifkan strict_types memberi kemungkinan perilaku yang diharapkan dan diinginkan:

<?php declare(strict_types=1);

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

Hasil:

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

Saya pikir ada dua pelajaran di sini, jika Anda menggunakan petunjuk ketik:

  • Gunakan strict_types=1selalu.
  • Konversikan pemberitahuan menjadi pengecualian, jika Anda lupa menambahkan strict_typespragma.
uskup
sumber
1
Ini sudah dijawab dengan baik hampir setahun yang lalu;)
emix
6
Memang, saya memilih jawaban lain @emix. Namun, saya merasa pertanyaan "haruskah saya melakukannya" tidak tersentuh. Saya juga merasakan contoh yang lebih ringkas dan mengejutkan akan mendorong orang untuk menggunakannya strict_types.
Uskup
1
Saya pikir pertanyaan ini dengan singkat menjawab, "Haruskah saya melakukannya?" bagian dari pertanyaan OP. Kembali ke PHP setelah sedikit jeda dan ini sangat membantu.
Darragh Enright