is_a กับ instanceof ต่างกันอย่างไร


205

ฉันรู้ว่าinstanceofเป็นผู้ดำเนินการและis_aเป็นวิธีการ

วิธีนี้ช้าลงในประสิทธิภาพหรือไม่? คุณต้องการใช้อะไร


15
is_a () อาจช้าลง - แต่คุณสามารถโทรหามันได้โดยใช้ call_user_func () ในขณะที่ instanceof ไม่สามารถเรียกได้ว่าเป็นแบบนี้ ...
Kamil Tomšík

คำตอบ:


211

ปรับปรุง

ตั้งแต่PHP 5.3.9ฟังก์ชันของis_a()เปลี่ยนไป คำตอบเดิมด้านล่างระบุว่าis_a() ต้องยอมรับObjectว่าเป็นอาร์กิวเมนต์แรก แต่รุ่น PHP> = 5.3.9 ตอนนี้ยอมรับอาร์กิวเมนต์บูลีนที่สามเป็นตัวเลือก$allow_string(ค่าเริ่มต้นเป็นfalse) เพื่ออนุญาตการเปรียบเทียบชื่อคลาสสตริงแทน:

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

ความแตกต่างที่สำคัญในการทำงานใหม่ระหว่างinstanceofและis_a()คือการที่instanceofจะตรวจสอบว่าเป้าหมายเป็นวัตถุ instantiated ของชั้นที่กำหนด (รวมถึงการขยายชั้นเรียน) ในขณะที่is_a()เพียงต้องการว่าวัตถุที่ถูก instantiated เมื่ออาร์กิวเมนต์ถูกตั้งค่าเริ่มต้นของ$allow_stringfalse


เป็นต้นฉบับ

ที่จริงแล้วis_aเป็นฟังก์ชั่นในขณะที่instanceofการสร้างภาษา is_aจะช้าลงอย่างมีนัยสำคัญ (เนื่องจากมีค่าใช้จ่ายทั้งหมดในการดำเนินการเรียกใช้ฟังก์ชัน) แต่เวลาดำเนินการโดยรวมมีเพียงเล็กน้อยในแต่ละวิธี

ไม่มีการคัดค้านแล้วในขณะที่ 5.3 ดังนั้นจึงไม่ต้องกังวล

มีข้อแตกต่างอย่างหนึ่งคือ is_aเป็นฟังก์ชั่นใช้วัตถุเป็นพารามิเตอร์ 1 และสตริง (ตัวแปรค่าคงที่หรือตัวอักษร) เป็นพารามิเตอร์ 2 ดังนั้น:

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

instanceof ใช้วัตถุเป็นพารามิเตอร์ 1 และสามารถใช้ชื่อคลาส (ตัวแปร), อินสแตนซ์ของวัตถุ (ตัวแปร) หรือตัวระบุคลาส (ชื่อคลาสที่เขียนโดยไม่มีเครื่องหมายคำพูด) เป็นพารามิเตอร์ 2

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

36
ทำไมไม่ได้รับการis_aชดเชย
Theodore R. Smith

21
@ theodore-r-smith ตามเอกสารประกอบว่า "ได้รับการยกเลิกโดยคำขอยอดนิยม" php.net/manual/en/migration53.undeprecated.php
Janci

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

39
อีกสิ่งหนึ่งที่ควรทราบเกี่ยวกับis_avs instanceofโอเปอเรเตอร์คือการis_aยอมรับนิพจน์สำหรับพารามิเตอร์ที่สองในขณะที่อินสแตนซ์ของเคย ตัวอย่างเช่นการis_a($object, 'Prefix_'.$name)ทำงานในขณะที่$object instanceof 'Prefix_'.$nameไม่
Evan Purkhiser

6
is_aไม่ควรเลิกใช้ตั้งแต่แรก มันสายไปหน่อยที่จะซ่อมมันตอนนี้ ปัญหาคือinstanceofผู้ประกอบการพ่นข้อผิดพลาดทางไวยากรณ์ใน PHP 4 และเนื่องจากis_aถูกคัดค้านในเวลาเดียวกับที่ผู้ประกอบการได้เปิดตัวมันเป็นไปไม่ได้ที่จะเขียนรหัสสำหรับทั้ง PHP 4 และ 5 โดยไม่ต้องโยน E_STRICT คุณไม่สามารถทำได้if (version_compare(PHP_VERSION, 5) >= 0) { /* use instanceof */ } else { /* use is_a */ }เพราะมันจะทำให้เกิดข้อผิดพลาดทางไวยากรณ์ใน PHP 4
meustrus

47

นี่คือผลการดำเนินงานของis_a ()และตัวอย่างของ :

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

แหล่งที่มาทดสอบเป็นที่นี่


6
กล่าวอีกนัยหนึ่งความแตกต่างนั้นสำคัญหากคุณต้องการประหยัด ~ 0.015 วินาทีต่อการใช้งาน 10,000 ครั้ง
CJ Dennis

1
เนื่องจากphp 7ไม่มีความแตกต่าง
MAX

@CJDennis จากประสบการณ์เมื่อทุกคนคิดเช่นนี้ผลิตภัณฑ์สุดท้ายจะช้ากว่าที่คาดไว้ (เซิร์ฟเวอร์ Soft + OS + ไม่ได้เพิ่มประสิทธิภาพ) โปรดจำไว้ว่าเวลาที่เพิ่มนั้นไม่ได้เป็นเชิงเส้นเสมอไป แต่สามารถอธิบายได้ มีจิตใจที่ดีเสมอ
โตโต้

@Toto มีโพสต์บล็อกที่ยอดเยี่ยมเกี่ยวกับสิ่งที่นักพัฒนาที่มีประสบการณ์สามารถเรียนรู้จากผู้เริ่มต้น หวังว่าคุณจะเห็นมันที่มุมขวาบน ระวังการเพิ่มประสิทธิภาพก่อนวัยอันควร! แก้ไขปัญหาเกี่ยวกับเวลาหลังจากที่กลายเป็นปัญหาเท่านั้น! หากประสิทธิภาพเป็นที่ยอมรับอย่าใช้เวลาเปลี่ยน!
CJ Dennis

10

instanceofสามารถใช้กับอินสแตนซ์ของวัตถุอื่น ๆ ชื่อของคลาสหรืออินเทอร์เฟซ ฉันไม่คิดว่าใช้is_a()งานได้กับอินเทอร์เฟซ (เฉพาะสตริงที่แสดงชื่อคลาส) แต่แก้ไขให้ถูกต้องถ้าเป็นเช่นนั้น (อัปเดต: ดูhttps://gist.github.com/1455148 )

ตัวอย่างจาก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'

เอาท์พุท:

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

3
is_aทำงานกับอินเทอร์เฟซเช่นเดียวกับinstanceof(ฉันจะพูดในสิ่งเดียวกัน แต่ฉันตรวจสอบก่อนส่งและมันใช้งานได้จริง) ...
ircmaxell

2
-1 โปรดสรุปการอัปเดตแทนที่จะเชื่อมโยงกับส่วนสำคัญ นั่นไม่เป็นประโยชน์สำหรับคนที่พยายามเรียนรู้
Erick Robertson

5

ในส่วนที่เกี่ยวกับคำตอบของ ChrisF นั้นis_a() จะไม่ถูกคัดค้านณ PHP 5.3.0 อีกต่อไป ฉันพบว่ามันปลอดภัยกว่าถ้าจะใช้แหล่งข้อมูลอย่างเป็นทางการสำหรับสิ่งนี้

สำหรับคำถามของคุณดาเนียลฉันไม่สามารถพูดเกี่ยวกับความแตกต่างในการทำงานได้ แต่ส่วนหนึ่งจะทำให้อ่านง่ายและคุณหางานได้ง่ายขึ้น

นอกจากนี้ยังมีการอภิปรายเกี่ยวกับความสับสนรอบกวนตรวจสอบเทียบinstanceof is_a()ตัวอย่างเช่นinstanceofคุณจะทำ:

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

vs ต่อไปนี้สำหรับis_a():

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

หรือ

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

แก้ไขดูเหมือนว่า ChrisF จะลบคำตอบของเขา แต่ส่วนแรกของคำตอบของฉันยังคงอยู่


5

นอกจากความเร็วแล้วความแตกต่างที่สำคัญอีกอย่างก็คือวิธีจัดการกับเคสแบบขอบ

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.

ดังนั้น is_a () จะเน้นข้อบกพร่องที่เป็นไปได้ขณะที่อินสแตนซ์ของยับยั้งพวกเขา


2

การเพิ่มประสิทธิภาพน้อยที่สุด และการเพิ่มประสิทธิภาพขนาดเล็กนั้นไม่ใช่คำตอบที่ดีจริง ๆ ต่อหน้าความสามารถในการอ่านความเข้าใจและความเสถียรของโค้ด

(โดยส่วนตัวแล้วฉันต้องการอินสแตนซ์ก่อน แต่ตัวเลือกเป็นของคุณ))

ความแตกต่างหลักคือความเป็นไปได้ที่จะใช้ชื่อคลาสโดยตรงกับอินสแตนซ์ของ

$ a instanceof MyClass

สั้นกว่า

is_a ($ a, MyClass :: คลาส)

(ตกลง…มันไม่สำคัญเลย)

สีของไวยากรณ์ระหว่าง instanceof (โครงสร้างภาษา) และ is_a นั้นมีประโยชน์เช่นกัน (สำหรับฉัน) ปล่อยให้สีของฟังก์ชั่นทำงานใหญ่ขึ้น และสำหรับการใช้งานครั้งเดียวในถ้าอินสแตนซ์ของ dos ไม่จำเป็นต้องใช้วงเล็บมากขึ้น

หมายเหตุ: แน่นอนแทนที่จะเป็นคลาส MyClass :: คุณสามารถใช้สตริงโดยตรงที่สั้นกว่า:

is_a ($ a 'MyClass')

แต่ใช้สตริงโดยตรงในรหัสไม่ได้เป็นวิธีที่ดี

การจัดเรียงทางไวยากรณ์นั้นดีกว่าและมีประโยชน์มากกว่าหากคุณสามารถสร้างความแตกต่างระหว่างชื่อสตริงและคลาสอย่างง่าย และง่ายต่อการเปลี่ยนชื่อด้วยชื่อคงที่ พิเศษถ้าคุณใช้เนมสเปซกับนามแฝง

ดังนั้นเราจะใช้is_a () ได้อย่างไร

สำหรับ raison ที่เหมือนกัน: การอ่านและ undestandability (เป็นทางเลือกของคุณ) พิเศษเมื่อใช้กับ! หรือตัวดำเนินการบูลีนอื่น ๆ : is_aดูเหมือนจะเป็นจริงมากขึ้นด้วยวงเล็บ

if ($ a AND (! is_a ($ a, MyClass :: class) หรือ is_a ($ a, MyOtherClass :: class)))

สามารถอ่านได้มากกว่า:

if ($ a AND (! ($ a instanceof MyClass) หรือ ($ a intanceof MyOtherClass))

อีกเหตุผลที่ดีคือเมื่อคุณต้องการใช้โทรกลับในฟังก์ชั่น (เช่นarray_map ... ) instanceofไม่ใช่ฟังก์ชัน แต่เป็นโครงสร้างภาษาดังนั้นคุณจึงไม่สามารถใช้เป็น callback ได้

ในกรณีเหล่านี้is_aอาจมีประโยชน์


1

ฉันไม่สามารถพูดเพื่อให้ได้ประสิทธิภาพ - ฉันไม่ได้วัดอะไรเลย - แต่ขึ้นอยู่กับสิ่งที่คุณกำลังพยายามที่มีข้อ จำกัด instanceofด้วย ลองดูคำถามของฉันเมื่อเร็ว ๆ นี้เกี่ยวกับ:

PHP 'instanceof' ล้มเหลวโดยมีค่าคงที่คลาส

ฉันลงเอยด้วยการใช้is_aแทน ฉันชอบโครงสร้างที่instanceofดีกว่า (ฉันคิดว่ามันอ่านได้ดีกว่า) และจะใช้ต่อไปในที่ที่ฉันสามารถทำได้


1

นี่คือผลการดำเนินงานที่ได้รับจากที่นี่ :

instanceof เร็วกว่า.

ฟังก์ชั่น

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

ครั้ง (เรียกใช้ 5000 ครั้งในแต่ละครั้ง)

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

1

มีสถานการณ์จำลองที่ใช้is_a()งานได้เท่านั้นและinstanceofจะล้มเหลว

instanceof ต้องการชื่อคลาสที่แท้จริงหรือตัวแปรที่เป็นวัตถุหรือสตริง (ที่มีชื่อของคลาส) เป็นอาร์กิวเมนต์ที่ถูกต้อง

แต่ถ้าคุณต้องการระบุสตริงของชื่อคลาสจากการเรียกฟังก์ชันมันจะไม่ทำงานและส่งผลให้เกิดข้อผิดพลาดทางไวยากรณ์

is_a()อย่างไรก็ตามสถานการณ์เดียวกันทำงานได้ดีกับ

ตัวอย่าง:

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

สิ่งนี้ใช้ PHP 7.2.14

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.