Bagaimana mengatasi "harus berupa instance dari string, string yang diberikan" sebelum PHP 7?

217

Ini kode saya:

function phpwtf(string $s) {
    echo "$s\n";
}
phpwtf("Type hinting is da bomb");

Yang menghasilkan kesalahan ini:

Kesalahan fatal yang dapat ditangkap: Argumen 1 yang diteruskan ke phpwtf () harus berupa string, string yang diberikan

Lebih dari Orwellian kecil melihat PHP mengenali dan menolak jenis yang diinginkan dengan cara yang sama. Ada lima lampu, sial.

Apa yang setara dengan tipe hinting untuk string di PHP? Pertimbangan bonus untuk jawaban yang menjelaskan apa yang sebenarnya terjadi di sini.

leepower
sumber
5
Ya, itu karena Anda melakukan kesalahan. Kode Anda seharusnya tidak berfungsi, untuk memulainya. Baca tentang jenis juggling di dokumen PHP. PHP diketik secara dinamis dan diketik lemah. Anda dapat menggunakan (string) untuk melemparkan argumen ke string (hanya dalam fungsi tubuh sekalipun) tetapi Anda hanya bisa memberi petunjuk objek dan array seperti yang Anda lakukan dalam potongan kode Anda.
Richard Knop
7
Masalahnya adalah Anda membuat kesalahan kecil. Ada empat lampu!
CJ Dennis
@ Gordon, saya diuji pada 5.6. Masih belum berhasil.
Pacerier
@Pacerier Silakan ikuti wiki.php.net/rfc untuk perkembangan terbaru.
Gordon
3
Rupanya, skalar type-hinting (seperti OP secara intuitif diharapkan menjadi hal di atas) akhirnya telah disetujui di bawah RFC untuk PHP * 7 * menurut sumber . RFC yang disetujui ternyata juga menyediakan gula sintaksis untuk nilai-nilai pengembalian pengecekan tipe serta parameter (argumen). Sudah lama datang.
SeldomNeedy

Jawaban:

204

Sebelum PHP 7, mengisyaratkan tipe hanya dapat digunakan untuk memaksa jenis objek dan array. Tipe skalar tidak dapat diisyaratkan tipe. Dalam hal ini objek dari kelas stringdiharapkan, tetapi Anda memberikannya (skalar) string. Pesan kesalahan mungkin lucu, tapi itu seharusnya tidak berfungsi untuk memulai. Mengingat sistem pengetikan yang dinamis, ini sebenarnya masuk akal.

Anda hanya bisa secara manual "mengetikkan petunjuk" jenis skalar:

function foo($string) {
    if (!is_string($string)) {
        trigger_error('No, you fool!');
        return;
    }
    ...
}
tipuan
sumber
1
@menerima, Apakah ada sintaks untuk petunjuk tipe terbalik? Misalnya apa pun kecuali array.
Pacerier
@Pacerier Tidak, tidak ada.
tipuan
4
Jawaban ini tidak valid untuk PHP 7
Jose Nobile
24

Dari manual PHP :

Ketik Petunjuk hanya bisa dari jenis objek dan array (karena PHP 5.1). Petunjuk tipe tradisional dengan int dan string tidak didukung.

Jadi kamu memilikinya. Pesan kesalahannya tidak terlalu membantu, saya berikan itu.

** 2017 Edit **

PHP7 memperkenalkan lebih banyak deklarasi tipe data fungsi, dan tautan tersebut telah dipindahkan ke argumen Fungsi: Ketikkan deklarasi . Dari halaman itu:

Jenis yang valid

  • Nama kelas / antarmuka : Parameter harus berupa instance dari kelas atau nama antarmuka yang diberikan. (sejak PHP 5.0.0)
  • self : Parameter harus berupa instance dari kelas yang sama dengan yang didefinisikan oleh metode. Ini hanya dapat digunakan pada metode class dan instance. (sejak PHP 5.0.0)
  • Array : Parameter harus array. (sejak PHP 5.1.0) callable Parameter harus callable yang valid. PHP 5.4.0
  • bool : Parameter harus berupa nilai boolean. (sejak PHP 7.0.0)
  • float : Parameter harus berupa angka titik mengambang. (sejak PHP 7.0.0)
  • int : Parameter harus berupa bilangan bulat. (sejak PHP 7.0.0)
  • string : Parameter harus berupa string. (sejak PHP 7.0.0)
  • iterable : Parameter harus berupa array atau instance Traversable. (sejak PHP 7.1.0)

Peringatan

Alias ​​untuk jenis skalar di atas tidak didukung. Sebaliknya, mereka diperlakukan sebagai nama kelas atau antarmuka. Sebagai contoh, menggunakan boolean sebagai parameter atau tipe pengembalian akan membutuhkan argumen atau nilai pengembalian yang merupakan instance dari kelas atau antarmuka boolean, daripada tipe bool:

<?php
   function test(boolean $param) {}
   test(true);
 ?>

Contoh di atas akan menampilkan:

 Fatal error: Uncaught TypeError: Argument 1 passed to test() must be an instance of boolean, boolean given, called in - on line 1 and defined in -:1

Peringatan terakhir sebenarnya penting untuk memahami kesalahan "Argumen harus bertipe string, string diberikan"; karena sebagian besar hanya nama kelas / antarmuka diizinkan sebagai tipe argumen, PHP mencoba mencari nama kelas "string", tetapi tidak dapat menemukannya karena ini adalah tipe primitif, sehingga gagal dengan kesalahan canggung ini.

Yanick Rochon
sumber
8

PHP memungkinkan "memberi isyarat" di mana Anda menyediakan kelas untuk menentukan objek. Menurut manual PHP, "Tip Petunjuk hanya bisa dari tipe objek dan array (karena PHP 5.1). Tipe tradisional yang mengisyaratkan int dan string tidak didukung." Kesalahan membingungkan karena pilihan Anda "string" - menempatkan "myClass" di tempatnya dan kesalahan akan berbunyi berbeda: "Argumen 1 diteruskan ke phpwtf () harus menjadi instance dari myClass, string diberikan"

Mimpi nyata
sumber
3

Seperti yang telah dikatakan orang lain, tipe hinting saat ini hanya berfungsi untuk tipe objek. Tapi saya pikir kesalahan tertentu yang Anda picu mungkin dalam persiapan tipe string mendatang SplString .

Secara teori itu berperilaku seperti string, tetapi karena itu adalah objek akan melewati verifikasi tipe objek. Sayangnya itu belum dalam PHP 5.3, mungkin datang dalam 5,4, jadi belum menguji ini.

mario
sumber
2

Sebagai PHP 7.0 deklarasi tipe memungkinkan jenis skalar, sehingga jenis ini sekarang tersedia: self, array, callable, bool, float, int, string. Tiga yang pertama tersedia di PHP 5, tetapi empat yang terakhir baru dalam PHP 7. Jika Anda menggunakan hal lain (misalnya integeratau boolean) yang akan ditafsirkan sebagai nama kelas.

Lihat manual PHP untuk informasi lebih lanjut .

TwoStraws
sumber
0

Mungkin tidak aman dan cantik tetapi jika Anda harus:

class string
{
    private $Text;
    public function __construct($value)
    {
        $this->Text = $value;
    }

    public function __toString()
    {
        return $this->Text;
    }
}

function Test123(string $s)
{
    echo $s;
}

Test123(new string("Testing"));
Patrick
sumber
5
Saya masih bisa membuatnew string(array(1,2,3))
Jimmy T.
0

Saya mendapatkan kesalahan ini ketika menjalankan fungsi dari Laravel Controller ke file PHP.

Setelah beberapa jam, saya menemukan masalah: Saya menggunakan $ this dari dalam fungsi statis.

ecairol
sumber
Using $this when not in object contextmemang pesan samar.
Ben Fransen
0

(awalnya diposting oleh leepowers dalam pertanyaannya)

Pesan kesalahan membingungkan karena satu alasan besar:

Nama tipe primitif tidak disediakan dalam PHP

Berikut ini adalah semua deklarasi kelas yang valid:

class string { }
class int { }
class float { }
class double { }

Kesalahan saya adalah berpikir bahwa pesan kesalahan merujuk semata-mata ke tipe primitif string - kata 'instance' seharusnya membuat saya berhenti. Contoh untuk menggambarkan lebih lanjut:

class string { }
$n = 1234;
$s1 = (string)$n;
$s2 = new string();
$a = array('no', 'yes');
printf("\$s1 - primitive string? %s - string instance? %s\n",
        $a[is_string($s1)], $a[is_a($s1, 'string')]);
printf("\$s2 - primitive string? %s - string instance? %s\n",
        $a[is_string($s2)], $a[is_a($s2, 'string')]);

Keluaran:

$ s1 - string primitif? ya - string misalnya? tidak

$ s2 - string primitif? contoh tanpa string? Iya

Dalam PHP dimungkinkan untuk stringmenjadi stringkecuali ketika itu sebenarnya a string. Seperti bahasa apa pun yang menggunakan konversi tipe implisit, konteks adalah segalanya.

pengguna719662
sumber
-1

Saya pikir typecasting pada php pada blok di dalam, String pada PHP bukan objek seperti yang saya tahu:

<?php
function phpwtf($s) {
    $s = (string) $s;
    echo "$s\n";
}
phpwtf("Type hinting is da bomb");
subosito
sumber
2
Anda dapat menambahkan validasi is_string () di dalam fungsi Anda untuk mencegah nilai lain diteruskan ke fungsi.
subosito
1
(string) $sdapat melempar kesalahan jika $smerupakan objek yang tidak dapat dilemparkan ke dalam string (tidak memiliki __toString()metode yang diterapkan), jadi tidak semudah itu
Yanick Rochon
Ya Yanick kamu benar. Tapi kita tidak bisa memaksa semua input menjadi string, kan? itu sebabnya pengecualian datang untuk bermain. Kita dapat menggabungkan semacam validasi dan menangkap pengecualian untuk sisanya;)
subosito
Saya hanya mengatakan bahwa casting beberapa variabel ke string tanpa memeriksa terlebih dahulu jika variabel dapat dilemparkan harus dihindari, terutama karena menangkap pengecualian mahal dan mengarah ke pola desain yang buruk / kebiasaan pengkodean.
Yanick Rochon