Sự khác biệt giữa is_a và instanceof là gì?


205

Tôi biết rằng đó instanceoflà một toán tử và đó is_alà một phương pháp.

Là phương pháp chậm hơn trong hiệu suất? Bạn thích sử dụng cái gì?


15
is_a () có thể chậm hơn - nhưng bạn có thể gọi nó bằng cách sử dụng call_user_func () trong khi thể hiện không thể được gọi theo cách này ...
Kamil Tomšík

Câu trả lời:


211

Cập nhật

Kể từ phiên bản PHP 5.3.9 , chức năng của is_a()đã thay đổi. Câu trả lời ban đầu bên dưới nói rằng is_a() phải chấp nhận một Objectđối số đầu tiên, nhưng các phiên bản PHP> = 5.3.9 hiện chấp nhận một đối số boolean thứ ba tùy chọn $allow_string(mặc định false) để cho phép so sánh các tên lớp chuỗi thay thế:

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);

Sự khác biệt chính trong hành vi mới giữa instanceofis_a()instanceofsẽ luôn kiểm tra xem mục tiêu có phải là đối tượng được khởi tạo của lớp được chỉ định (bao gồm cả các lớp mở rộng) hay không, trong khi is_a()chỉ yêu cầu đối tượng được khởi tạo khi $allow_stringđối số được đặt thành giá trị mặc định false.


Nguyên

Trên thực tế, is_alà một chức năng, trong khi đó instanceoflà một cấu trúc ngôn ngữ. is_asẽ chậm hơn đáng kể (vì nó có toàn bộ chi phí thực hiện lệnh gọi hàm), nhưng thời gian thực hiện chung là tối thiểu trong cả hai phương thức.

Nó không còn bị phản đối kể từ ngày 5.3, vì vậy không có gì phải lo lắng ở đó.

Tuy nhiên, có một sự khác biệt. is_alà một hàm lấy một đối tượng làm tham số 1 và một chuỗi (biến, hằng hoặc bằng chữ) làm tham số 2. Vì vậy:

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

instanceof lấy một đối tượng làm tham số 1 và có thể lấy tên lớp (biến), thể hiện đối tượng (biến) hoặc định danh lớp (tên lớp được viết không có dấu ngoặc kép) làm tham số 2.

$object instanceof $string;      // <- string class name
$object instanceof $otherObject; // <- object instance
$object instanceof ClassName;    // <- identifier for the class

36
Tại sao không được is_ađánh giá cao?
Theodore R. Smith

21
@ theodore-r-smith Theo tài liệu nó "đã được undeprecated theo yêu cầu phổ biến" php.net/manual/en/migration53.undeprecated.php
Janci

3
@danip$class = 'Foo'; var_dump($obj instanceof $class);
ircmaxell

39
Một điều nữa cần lưu ý về is_avs instanceoftoán tử là is_asẽ chấp nhận các biểu thức cho tham số thứ hai, trong khi instanceof sẽ không. Ví dụ is_a($object, 'Prefix_'.$name)hoạt động trong khi $object instanceof 'Prefix_'.$namekhông
Evan Purkhiser 25/03/13

6
is_akhông bao giờ nên bị từ chối ở nơi đầu tiên. Bây giờ đã muộn một chút để sửa nó. Vấn đề là instanceoftoán tử ném lỗi cú pháp trong PHP 4 và do is_akhông được dùng cùng lúc với toán tử được giới thiệu nên không thể viết mã cho cả PHP 4 và 5 mà không ném E_STRICT. Bạn thậm chí không thể làm được if (version_compare(PHP_VERSION, 5) >= 0) { /* use instanceof */ } else { /* use is_a */ }vì nó vẫn gây ra lỗi cú pháp trong PHP 4.
meustrus 20/03/2015

47

Đây là kết quả hoạt động của is_a ()instanceof :

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

Nguồn kiểm tra là đây .


6
Nói cách khác, sự khác biệt chỉ quan trọng nếu bạn cần tiết kiệm ~ 0,015 giây trên 10000 lần sử dụng.
CJ Dennis

1
Như php 7không có sự khác biệt.
MAX

@CJDennis Theo kinh nghiệm, khi mọi người nghĩ như thế này, sản phẩm cuối cùng sẽ chậm hơn dự kiến. (Máy chủ Soft + OS + không được tối ưu hóa). Hãy nhớ rằng thời gian được thêm vào không phải lúc nào cũng tuyến tính, nhưng có thể theo cấp số nhân. Luôn luôn có sự tinh tế trong tâm trí.
Toto

@Toto Có một bài đăng blog tuyệt vời về những gì các nhà phát triển có kinh nghiệm có thể học hỏi từ những người mới bắt đầu. Hy vọng bạn có thể nhìn thấy nó ở trên cùng bên phải. Coi chừng tối ưu hóa sớm! Chỉ giải quyết vấn đề thời gian sau khi chúng trở thành vấn đề ! Nếu hiệu suất được chấp nhận như hiện tại, đừng dành thời gian thay đổi nó!
CJ Dennis

10

instanceofcó thể được sử dụng với các thể hiện đối tượng khác, tên lớp hoặc giao diện. Tôi không nghĩ rằng nó is_a()hoạt động với các giao diện (chỉ một chuỗi đại diện cho một tên lớp), nhưng sửa lại cho tôi nếu nó đúng. (Cập nhật: Xem https://gist.github.com/1455148 )

Ví dụ từ 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'

đầu ra:

bool(true)
bool(true)
bool(false)

3
is_akhông hoạt động với các giao diện giống như instanceof(tôi sẽ nói điều tương tự, nhưng tôi đã kiểm tra nó trước khi gửi, và nó thực sự hoạt động) ...
ircmaxell

2
-1 xin vui lòng tóm tắt bản cập nhật thay vì chỉ liên kết với một ý chính. Điều đó là vô ích cho những người cố gắng học hỏi.
Erick Robertson

5

Liên quan đến câu trả lời của ChrisF, is_a() không còn bị phản đối kể từ phiên bản PHP 5.3.0. Tôi thấy nó luôn an toàn hơn khi đi theo nguồn chính thức cho những thứ như thế này.

Liên quan đến câu hỏi của bạn, Daniel, tôi không thể nói về sự khác biệt về hiệu suất, nhưng một phần của câu hỏi sẽ dễ đọc và bạn thấy dễ làm việc hơn.

Ngoài ra, có một số cuộc thảo luận về sự nhầm lẫn xung quanh việc phủ định một instanceofséc so với is_a(). Ví dụ, đối với instanceofbạn sẽ làm:

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

so với sau đây cho is_a():

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

hoặc là

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

Chỉnh sửa Có vẻ như ChrisF đã xóa câu trả lời của anh ấy, nhưng phần đầu tiên trong câu trả lời của tôi vẫn đứng vững.


5

Bên cạnh tốc độ, một sự khác biệt quan trọng khác là cách họ xử lý các trường hợp cạnh.

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.

Vì vậy, is_a () nêu bật các lỗi có thể xảy ra trong khi instanceof loại bỏ chúng.


2

Việc tối ưu hóa là tối thiểu. Và tối ưu hóa vi mô không bao giờ là một câu trả lời thực sự tốt, trước khả năng đọc, dễ hiểu và ổn định của mã.

(cá nhân tôi là ví dụ trước , nhưng sự lựa chọn là của bạn;))

Sự khác biệt chính là khả năng sử dụng tên lớp trực tiếp với instanceof

$ một ví dụ của MyClass

ngắn hơn

is_a ($ a, MyClass :: class)

(ok, nó không tầm thường.)

Màu sắc cú pháp giữa instanceof (cấu trúc ngôn ngữ) và is_a cũng hữu ích (đối với tôi). cho phép màu sắc chức năng để hoạt động lớn hơn. Và để sử dụng một lần trong if, instanceof dos không cần thêm dấu ngoặc đơn.

Lưu ý: Tất nhiên thay vì MyClass :: class, bạn có thể sử dụng chuỗi trực tiếp ngắn hơn:

is_a ($ a, 'MyClass')

Nhưng sử dụng chuỗi trực tiếp trong một mã không phải là một thực hành tốt .

Việc thu thập cú pháp tốt hơn và hữu ích hơn nếu bạn có thể tạo sự khác biệt giữa tên chuỗi đơn giản và tên lớp. Và nó dễ dàng hơn để thay đổi tên với tên lớp không đổi. Đặc biệt nếu bạn sử dụng không gian tên với bí danh.

Vì vậy, wy sử dụng is_a () ?

Đối với cùng một tù nhân: khả năng đọc và không thể phá hủy. (sự lựa chọn là của bạn) Đặc biệt khi sử dụng với ! hoặc các toán tử boolean khác: is_a có vẻ hợp lý hơn với dấu ngoặc đơn.

if ($ a AND (! is_a ($ a, MyClass :: class) HOẶC is_a ($ a, MyOtherClass :: class)))

dễ đọc hơn:

if ($ a AND (! ($ a instanceof MyClass) HOẶC ($ a intanceof MyOtherClass)))

Một lý do tốt khác là khi bạn cần sử dụng gọi lại trong các chức năng. (Như array_map ...) instanceof không phải là một chức năng, đó là một cấu trúc ngôn ngữ, vì vậy bạn không thể sử dụng nó như là gọi lại.

Trong trường hợp those, is_a có thể hữu ích


1

Tôi không thể nói về hiệu suất - Tôi chưa đo bất cứ điều gì - nhưng tùy thuộc vào những gì bạn đang cố gắng, có những hạn chế instanceof. Kiểm tra câu hỏi của tôi, chỉ gần đây, về nó:

PHP 'instanceof' thất bại với hằng số lớp

Tôi đã kết thúc bằng cách sử dụng is_athay thế. Tôi thích cấu trúc instanceoftốt hơn (tôi nghĩ nó đọc đẹp hơn) và sẽ tiếp tục sử dụng nó ở nơi tôi có thể.


1

Dưới đây là kết quả hiệu suất thu được từ đây :

instanceof nhanh hơn.

Chức năng

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';
}

Lần (chạy 5000 lần mỗi lần)

0.00573397 // method_1(5) 
0.01437402 // method_2(5) 
0.00376201 // method_3(5)

1

Có một kịch bản chỉ is_a()hoạt động và instanceofsẽ thất bại.

instanceof mong đợi một tên lớp theo nghĩa đen hoặc một biến là một đối tượng hoặc một chuỗi (với tên của một lớp) là đối số đúng của nó.

Nhưng nếu bạn muốn cung cấp chuỗi tên lớp từ một hàm gọi thì nó sẽ không hoạt động và dẫn đến lỗi cú pháp.

Tuy nhiên, kịch bản tương tự hoạt động tốt với is_a().

Thí dụ:

<?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()));

Điều này dựa trên PHP 7.2,14.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.