Apa perbedaan antara is_a dan instanceof?

205

Saya sadar itu instanceofadalah operator dan itu is_aadalah metode.

Apakah metode ini lebih lambat kinerjanya? Apa yang ingin Anda gunakan?

Daniel
sumber
15
is_a () bisa lebih lambat - tetapi Anda dapat menyebutnya menggunakan call_user_func () sementara instanceof tidak dapat dipanggil dengan cara ini ...
Kamil Tomšík

Jawaban:

211

Memperbarui

Pada PHP 5.3.9 , fungsionalitas is_a()telah berubah. Jawaban asli di bawah ini menyatakan bahwa is_a() harus menerima Objectargumen pertama, tetapi versi PHP> = 5.3.9 sekarang menerima argumen opsional boolean ketiga $allow_string(default untuk false) untuk memungkinkan perbandingan nama kelas string sebagai gantinya:

class MyBaseClass {}
class MyExtendingClass extends MyBaseClass {}

// Original behavior, evaluates to false.
is_a(MyExtendingClass::class, MyBaseClass::class);

// New behavior, evaluates to true.
is_a(MyExtendingClass::class, MyBaseClass::class, true);

Perbedaan utama dalam perilaku baru antara instanceofdan is_a()adalah bahwa instanceofakan selalu memeriksa bahwa target adalah objek instantiated dari kelas yang ditentukan (termasuk memperluas kelas), sedangkan is_a()hanya mensyaratkan bahwa objek akan dipakai saat $allow_stringargumen diatur ke nilai default false.


Asli

Sebenarnya, is_aadalah fungsi, sedangkan instanceofbahasa adalah konstruksi. is_aakan secara signifikan lebih lambat (karena memiliki semua overhead menjalankan panggilan fungsi), tetapi waktu eksekusi keseluruhan minimal dalam kedua metode.

Tidak lagi usang pada 5.3, jadi tidak ada kekhawatiran di sana.

Namun ada satu perbedaan. is_amenjadi fungsi mengambil objek sebagai parameter 1, dan string (variabel, konstan, atau literal) sebagai parameter 2. Jadi:

is_a($object, $string); // <- Only way to call it

instanceof mengambil objek sebagai parameter 1, dan dapat mengambil nama kelas (variabel), instance objek (variabel), atau pengidentifikasi kelas (nama kelas ditulis tanpa tanda kutip) sebagai parameter 2.

$object instanceof $string;      // <- string class name
$object instanceof $otherObject; // <- object instance
$object instanceof ClassName;    // <- identifier for the class
ircmaxell
sumber
36
Mengapa tidak is_apantas?
Theodore R. Smith
21
@ theodore-r-smith Menurut dokumentasi itu "tidak dapat diterima oleh permintaan populer" php.net/manual/en/migration53.undeprecated.php
Janci
3
@danip$class = 'Foo'; var_dump($obj instanceof $class);
ircmaxell
39
Satu hal lagi yang perlu diperhatikan tentang is_avs instanceofoperator adalah yang is_aakan menerima ekspresi untuk parameter kedua, sementara instance tidak akan. Misalnya is_a($object, 'Prefix_'.$name)berfungsi sementara $object instanceof 'Prefix_'.$nametidak
Evan Purkhiser
6
is_aseharusnya tidak pernah ditinggalkan sejak awal. Ini agak terlambat untuk memperbaikinya sekarang. Masalahnya adalah bahwa instanceofoperator melempar kesalahan sintaksis dalam PHP 4, dan karena is_asudah usang pada saat yang sama dengan operator diperkenalkan itu menjadi mustahil untuk menulis kode untuk PHP 4 dan 5 tanpa melemparkan E_STRICT sekitar. Anda bahkan tidak dapat melakukannya if (version_compare(PHP_VERSION, 5) >= 0) { /* use instanceof */ } else { /* use is_a */ }karena itu masih akan menyebabkan kesalahan sintaksis dalam PHP 4.
meustrus
47

Berikut ini adalah hasil kinerja is_a () dan instanceof :

Test name       Repeats         Result          Performance     
instanceof      10000           0.028343 sec    +0.00%
is_a()          10000           0.043927 sec    -54.98%

Sumber tes ada di sini .

Alexander Yancharuk
sumber
6
Dengan kata lain, perbedaannya hanya penting jika Anda perlu menghemat ~ 0,015 detik per 10.000 penggunaan.
CJ Dennis
1
Sampai php 7tidak ada perbedaan.
MAX
@CJDennis Berdasarkan pengalaman, ketika semua orang berpikir seperti ini, produk akhir akan lebih lambat dari yang diharapkan. (Soft + OS + server tidak dioptimalkan). Ingatlah bahwa waktu yang ditambahkan tidak selalu linier, tetapi dapat bersifat eksponensial. Selalu miliki kinerja dalam pikiran.
Toto
@Toto Ada posting blog yang bagus tentang apa yang bisa dipelajari oleh pengembang berpengalaman dari pemula. Semoga Anda bisa melihatnya di kanan atas. Waspadalah terhadap pengoptimalan prematur! Hanya selesaikan masalah waktu setelah masalah ! Jika kinerjanya dapat diterima sebagaimana adanya, jangan habiskan waktu untuk mengubahnya!
CJ Dennis
10

instanceofdapat digunakan dengan instance objek lain, nama kelas, atau antarmuka. Saya tidak berpikir itu is_a()bekerja dengan antarmuka (hanya string yang mewakili nama kelas), tetapi benar jika itu benar. (Pembaruan: Lihat https://gist.github.com/1455148 )

Contoh dari php.net :

interface MyInterface
{
}

class MyClass implements MyInterface
{
}

$a = new MyClass;
$b = new MyClass;
$c = 'MyClass';
$d = 'NotMyClass';

var_dump($a instanceof $b); // $b is an object of class MyClass
var_dump($a instanceof $c); // $c is a string 'MyClass'
var_dump($a instanceof $d); // $d is a string 'NotMyClass'

output:

bool(true)
bool(true)
bool(false)
Lotus Notes
sumber
3
is_atidak bekerja dengan antarmuka dengan cara yang sama seperti instanceof(saya akan mengatakan hal yang sama, tapi saya memeriksanya sebelum mengirimkan, dan itu memang berfungsi) ...
ircmaxell
2
-1 tolong rangkum pembaruan itu dari pada hanya menautkan ke inti. Itu tidak membantu bagi orang yang mencoba belajar.
Erick Robertson
5

Sehubungan dengan jawaban ChrisF, is_a() tidak lagi ditinggalkan pada PHP 5.3.0. Saya menemukan selalu lebih aman untuk menggunakan sumber resmi untuk hal-hal seperti ini.

Berkenaan dengan pertanyaan Anda, Daniel, saya tidak bisa mengatakan tentang perbedaan kinerja, tetapi sebagian dari itu akan turun ke kesiapan dan yang Anda temukan lebih mudah untuk dikerjakan.

Juga, ada beberapa diskusi tentang kebingungan di sekitar meniadakan sebuah instanceofcek vs is_a(). Misalnya, untuk instanceofAnda lakukan:

<?php
if( !($a instanceof A) ) { //... }
?>

vs yang berikut untuk is_a():

<?php
if( !is_a($a, 'A' ) { //... }
?>

atau

<?php
if( is_a($a, 'A') === FALSE) { //... }
?>

Sunting Sepertinya ChrisF menghapus jawabannya, tetapi bagian pertama dari jawaban saya tetap ada.

Mike Branski
sumber
5

Selain kecepatan, perbedaan penting lainnya adalah bagaimana mereka menangani kasus tepi.

is_a($x1, $x2) // fatal error if x2 is not a string nor an object
$x1 instanceof $x2  // returns false even if $x2 is int, undefined, etc.

Jadi, is_a () menyoroti kemungkinan bug sementara instanceof menekannya.

Csongor Halmai
sumber
2

Optimalisasi minimal. Dan optimasi mikro tidak pernah merupakan jawaban yang benar-benar bagus, di depan keterbacaan, pemahaman dan stabilitas kode.

(Secara pribadi saya lebih suka contoh , tetapi pilihan ada di tangan Anda;))

Perbedaan utama adalah kemungkinan untuk menggunakan nama kelas langsung dengan instanceof

$ a instance dari MyClass

lebih pendek dari

is_a ($ a, MyClass :: class)

(ok ... itu tidak sepele.)

Warna sintaksis antara instanceof (struktur bahasa) dan is_a juga berguna (bagi saya). membiarkan warna fungsi untuk operasi yang lebih besar. Dan untuk penggunaan tunggal jika, misalnya, tidak perlu tanda kurung lagi.

Catatan: Tentu saja alih-alih kelas MyClass :: Anda dapat menggunakan string langsung yang lebih pendek:

is_a ($ a, 'MyClass')

Tetapi menggunakan string langsung dalam kode bukanlah praktik yang baik .

Kolokasi sintaksis lebih baik dan lebih berguna jika Anda dapat membuat perbedaan antara string sederhana dan nama kelas. Dan lebih mudah untuk mengubah nama dengan classname konstan. Khususnya jika Anda menggunakan namespace dengan alias.

Jadi, mengapa kita menggunakan is_a () ?

Untuk raison yang sama: keterbacaan dan undestandability. (Pilihan ada di tangan Anda) Terutama ketika digunakan dengan ! atau operator boolean lainnya: is_a tampaknya lebih praktis dengan tanda kurung.

if ($ a AND (! is_a ($ a, MyClass :: class) OR is_a ($ a, MyOtherClass :: class))))

lebih mudah dibaca daripada:

if ($ a AND (! ($ instanceof MyClass) ATAU ($ a intanceof MyOtherClass))))

Alasan bagus lainnya adalah ketika Anda perlu menggunakan fungsi panggil balik. (seperti array_map ...) instanceof bukan fungsi, ini adalah konstruksi bahasa, jadi Anda tidak dapat menggunakannya sebagai panggilan balik.

Dalam kasus ini, is_a mungkin berguna

Titsta
sumber
1

Saya tidak dapat berbicara untuk kinerja - saya belum mengukur apa pun - tetapi tergantung pada apa yang Anda coba, ada batasannya instanceof. Lihatlah pertanyaan saya, baru-baru ini, tentang hal itu:

PHP 'instanceof' gagal dengan konstanta kelas

Saya akhirnya menggunakan is_asebagai gantinya. Saya suka struktur yang instanceoflebih baik (saya pikir ini berbunyi lebih bagus) dan akan terus menggunakannya di mana saya bisa.

Nathan Loding
sumber
1

Berikut adalah hasil kinerja yang diperoleh dari sini :

instanceof lebih cepat.

Fungsi

function method_1($a = null) { 
    return is_object($a) && is_a($a, 'Example');
}

function method_2($a = null) {
    return is_a((object) $a, 'Example');
}

function method_3($a = null) {
    return $a instanceof 'Example';
}

Waktu (masing-masing berjalan 5000 kali)

0.00573397 // method_1(5) 
0.01437402 // method_2(5) 
0.00376201 // method_3(5)
dayuloli
sumber
1

Ada skenario di mana hanya is_a()berfungsi dan instanceofakan gagal.

instanceof mengharapkan nama kelas literal atau variabel yang merupakan objek atau string (dengan nama kelas) sebagai argumen yang benar.

Tetapi jika Anda ingin memberikan string nama kelas dari pemanggilan fungsi, itu tidak akan berfungsi dan menghasilkan kesalahan sintaksis.

Namun, skenario yang sama berfungsi dengan baik is_a().

Contoh:

<?php

function getClassName() : string
{
    return "Foobar";
}

class Foobar
{
    private $xyz;

}

$x = new Foobar();

// this works of course
var_dump($x instanceof Foobar);

// this creates a syntax error
var_dump($x instanceof getClassName());

// this works
var_dump(is_a($x, getClassName()));

Ini didasarkan pada PHP 7.2.14.

Erik Kalkoken
sumber