212

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

Phương pháp này có hiệu suất chậm hơn không? Bạn muốn 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ử call_user_func () trong khi instanceof không thể được gọi theo cách này ... –  11:43:14 06/02/2011
216

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 tuyên bố rằng is_a() phải chấp nhận một Objectlàm đố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 là 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 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 hàm, trong khi instanceoflà một cấu trúc ngôn ngữ. is_asẽ chậm hơn đáng kể (vì nó có tất cả chi phí thực hiện một lệnh gọi hàm), nhưng thời gian thực thi tổng thể là tối thiểu trong cả hai phương pháp.

Nó không còn bị phản đối kể từ phiên bản 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 nhận một đối tượng làm tham số 1 và một chuỗi (biến, hằng số hoặc chữ) làm tham số 2. Vì vậy:

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

instanceof nhận 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 mã đị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
|
  • 1
    Tại sao không được is_asử dụng? –  23:38:37 23/05/2012
  • 1
    @ 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 –  14:51:15 22/10/2012
  • 1
    @danip$class = 'Foo'; var_dump($obj instanceof $class); –  20:01:58 22/01/2013
  • 1
    Một điều nữa cần lưu ý về is_aso với instanceoftoán tử là is_asẽ chấp nhận các biểu thức cho tham số thứ hai, trong khi instanceof thì không. Ví dụ is_a($object, 'Prefix_'.$name)công trình khi $object instanceof 'Prefix_'.$namekhông –  05:38:51 25/03/2013
  • 1
    is_akhông bao giờ nên được chấp nhận ngay từ đầu. Tuy nhiên, đã hơi muộn để sửa chữa nó ngay bây giờ. Vấn đề là instanceoftoán tử ném ra các lỗi cú pháp trong PHP 4, và vì is_ađã không được chấp nhận cùng lúc khi 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 xung quanh. Bạn thậm chí không thể làm if (version_compare(PHP_VERSION, 5) >= 0) { /* use instanceof */ } else { /* use is_a */ }bởi vì nó vẫn có thể gây ra một lỗi cú pháp trong PHP 4. –  15:47:42 20/03/2015
51

Đây là kết quả hiệu suất 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 ở đây .

|
  • 1
    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 cho mỗi 10000 lần sử dụng. –  01:31:48 27/05/2018
  • 1
    Như php 7không có sự khác biệt. –  07:53:24 27/02/2019
  • 1
    @CJDennis Theo kinh nghiệm, khi mọi người đều nghĩ như vậy, sản phẩm cuối cùng sẽ chậm hơn dự kiến. (Máy chủ Soft + OS + chưa được tối ưu hóa). Hãy nhớ rằng thời gian 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ó hiệu suất trong tâm trí. –  22:33:13 22/12/2019
  • 1
    @Toto Có một bài đăng trên blog tuyệt vời về những điều mà các nhà phát triển có kinh nghiệm có thể học được từ những người mới bắt đầu. Hy vọng rằng bạn có thể nhìn thấy nó ở trên cùng bên phải. Cẩn thận với việc tối ưu hóa quá sớm! Chỉ giải quyết các vấn đề về thời gian sau khi chúng đã trở thành vấn đề ! Nếu hiệu suất có thể chấp nhận được, đừng tốn thời gian thay đổi nó! –  22:46:49 22/12/2019
10

instanceofcó thể được sử dụng với các cá thể đối tượng khác, tên của lớp hoặc một giao diện. Tôi không nghĩ rằng điều đó 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 hãy sửa lỗi cho tôi nếu nó có. (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'

kết quả đầu ra:

bool(true)
bool(true)
bool(false)
|
  • 1
    is_alàm việc với giao diện giống như instanceof(tôi sẽ nói điều tương tự, nhưng tôi đã kiểm tra trước khi gửi đi, và nó thực sự làm việc) ... –  19:27:26 10/06/2010
  • 1
    -1 hãy tóm tắt bản cập nhật thay vì chỉ liên kết đến một ý chính. Điều đó là vô ích cho những người cố gắng học hỏi. –  19:15:18 26/12/2013
6

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

Về 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 nó sẽ thuộc về khả năng 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ề những rắc rối xung quanh phủ một instanceofséc vs is_a(). Ví dụ, đối với instanceofbạn sẽ làm:

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

so với những điều 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 mình, nhưng phần đầu tiên của câu trả lời của tôi vẫn còn nguyên.

|
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 () làm nổi bật các lỗi có thể có trong khi instanceof ngăn chặn chúng.

|
2

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

instanceof yêu cầu 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àm đối số bên phải của nó.

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

Tuy nhiên, cùng một kịch bản hoạt động tốt 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.

|
2

Tối ưu hóa là tối thiểu. Và các 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 tính dễ đọc, dễ hiểu và tính ổn định của mã.

(tôi thích cá tính , 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

$ a instanceof MyClass

ngắn hơn

is_a ($ a, MyClass :: class)

(được rồi… 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 rất hữu ích (đối với tôi). cho phép màu chức năng cho các 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ì lớp MyClass :: bạn có thể sử dụng một 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ã không phải là một phương pháp hay .

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

Vì vậy, bạn có sử dụng is_a () không?

Đối với cùng một loại raison: 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ẻ thực dụng hơn với dấu ngoặc đơn.

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

dễ đọc hơn:

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

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

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

|
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

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

PHP 'instanceof' không thành công với hằng số lớp

Tôi đã kết thúc việc 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ó khi tôi có thể.

|

Câu trả lời của bạn (> 20 ký tự)

Bằng cách click "Đăng trả lời", bạn đồng ý với Điều khoản dịch vụ, Chính sách bảo mật and Chính sách cookie của chúng tôi.

Không tìm thấy câu trả lời bạn tìm kiếm? Duyệt qua các câu hỏi được gắn thẻ hoặc hỏi câu hỏi của bạn.