發布這個是為了讓 typeof 這個詞出現在這個頁面上,這樣當你用 Google 搜尋「php typeof」時,這個頁面就會出現。...是的,我以前是 Java 使用者。
instanceof
用於判斷 PHP 變數是否為某個類別的實例化物件
範例 #1 使用 instanceof
與類別
<?php
class MyClass
{
}
class NotMyClass
{
}
$a = new MyClass;
var_dump($a instanceof MyClass);
var_dump($a instanceof NotMyClass);
?>
上述範例會輸出:
bool(true) bool(false)
`instanceof` 也可用於判斷變數是否為繼承自父類別的類別之實例化物件。
範例 #2:將 `instanceof` 與繼承的類別一起使用
<?php
class ParentClass
{
}
class MyClass extends ParentClass
{
}
$a = new MyClass;
var_dump($a instanceof MyClass);
var_dump($a instanceof ParentClass);
?>
上述範例會輸出:
bool(true) bool(true)
要檢查物件是否「不是」某個類別的實例,可以使用 邏輯 `not` 運算子。
範例 #3:使用 `instanceof` 檢查物件是否「不是」某個類別的實例
<?php
class MyClass
{
}
$a = new MyClass;
var_dump(!($a instanceof stdClass));
?>
上述範例會輸出:
bool(true)
最後,`instanceof` 也可用於判斷變數是否為實作了 介面 (interface) 的類別之實例化物件。
範例 #4:將 `instanceof` 與介面一起使用
<?php
interface MyInterface
{
}
class MyClass implements MyInterface
{
}
$a = new MyClass;
var_dump($a instanceof MyClass);
var_dump($a instanceof MyInterface);
?>
上述範例會輸出:
bool(true) bool(true)
雖然 `instanceof` 通常與字面類別名稱一起使用,但它也可以與其他物件或字串變數一起使用。
範例 #5:將 `instanceof` 與其他變數一起使用
<?php
interface MyInterface
{
}
class MyClass implements MyInterface
{
}
$a = new MyClass;
$b = new MyClass;
$c = 'MyClass';
$d = 'NotMyClass';
var_dump($a instanceof $b); // $b 是 MyClass 類別的物件
var_dump($a instanceof $c); // $c 是字串 'MyClass'
var_dump($a instanceof $d); // $d 是字串 'NotMyClass'
?>
上述範例會輸出:
bool(true) bool(true) bool(false)
如果被測試的變數不是物件,instanceof 不會拋出任何錯誤,它只會回傳 false
。 然而,在 PHP 7.3.0 之前,常數是不允許的。
範例 #6 使用 instanceof
測試其他變數
<?php
$a = 1;
$b = NULL;
$c = imagecreate(5, 5);
var_dump($a instanceof stdClass); // $a 是一個整數
var_dump($b instanceof stdClass); // $b 是 NULL
var_dump($c instanceof stdClass); // $c 是一個資源
var_dump(FALSE instanceof stdClass);
?>
上述範例會輸出:
bool(false) bool(false) bool(false) PHP Fatal error: instanceof expects an object instance, constant given
從 PHP 7.3.0 開始,常數允許在 instanceof
運算子的左側。
範例 #7 使用 instanceof
測試常數
<?php
var_dump(FALSE instanceof stdClass);
?>
以上範例在 PHP 7.3 的輸出
bool(false)
從 PHP 8.0.0 開始,instanceof
現在可以用於任意表達式。該表達式必須以括號括起來,並產生一個 字串。
範例 #8 使用任意表達式搭配 instanceof
<?php
class ClassA extends \stdClass {}
class ClassB extends \stdClass {}
class ClassC extends ClassB {}
class ClassD extends ClassA {}
function getSomeClass(): string
{
return ClassA::class;
}
var_dump(new ClassA instanceof ('std' . 'Class'));
var_dump(new ClassB instanceof ('Class' . 'B'));
var_dump(new ClassC instanceof ('Class' . 'A'));
var_dump(new ClassD instanceof (getSomeClass()));
?>
以上範例在 PHP 8 中的輸出
bool(true) bool(true) bool(false) bool(true)
instanceof
運算子有一個功能變體,即 is_a() 函式。
發布這個是為了讓 typeof 這個詞出現在這個頁面上,這樣當你用 Google 搜尋「php typeof」時,這個頁面就會出現。...是的,我以前是 Java 使用者。
範例 #3 中,檢查一個物件不是某個類別的實例,使用了多餘的括號。
<?php
var_dump(!($a instanceof stdClass));
?>
由於 `instanceof` 的運算子優先順序高於 `!`,您可以直接這樣做:
<?php
var_dump( ! $a instanceof stdClass );
?>
您也可以使用 `instanceOf` 比較兩個物件。在這種情況下,`instanceOf` 會比較兩個物件的類型。這有時非常有用。
<?php
class A { }
class B { }
$a = new A;
$b = new B;
$a2 = new A;
echo $a instanceof $a; // true
echo $a instanceof $b; // false
echo $a instanceof $a2; // true
?>
我在這個頁面上沒有看到任何關於「命名空間」的說明,所以我想補充一下。當您將完整限定類別名稱 (FQCN) 作為字串而非簡單的類別名稱傳遞給 `instanceof` 運算子時,它會將其作為第二個運算元。即使您在頂層使用了 `use MyNamespace\Bar;`,它也不會解析它。我想表達的是以下內容:
## testinclude.php ##
<?php
namespace Bar1;
{
class Foo1{ }
}
namespace Bar2;
{
class Foo2{ }
}
?>
## test.php ##
<?php
include('testinclude.php');
use Bar1\Foo1 as Foo;
$foo1 = new Foo(); $className = 'Bar1\Foo1';
var_dump($foo1 instanceof Bar1\Foo1);
var_dump($foo1 instanceof $className);
$className = 'Foo';
var_dump($foo1 instanceof $className);
use Bar2\Foo2;
$foo2 = new Foo2(); $className = 'Bar2\Foo2';
var_dump($foo2 instanceof Bar2\Foo2);
var_dump($foo2 instanceof $className);
$className = 'Foo2';
var_dump($foo2 instanceof $className);
?>
## 標準輸出 ##
bool(true)
bool(true)
bool(false)
bool(true)
bool(true)
bool(false)
如果您只有類別名稱(而不是物件),您可以使用以下程式碼片段:https://3v4l.org/mUKUC
<?php
interface i{}
class a implements i{}
var_dump(a::class instanceof i); // false
var_dump(in_array(i::class, class_implements(a::class), true)); // true
在命名空間內執行 `$a instanceof stdClass` 將無法正常運作。
您必須這樣做
<?php
if ($a instanceof \stdClass)
?>
範例 #5 也可以擴展為包含...
var_dump($a instanceof MyInterface);
新的結果將會是
bool(true)
所以 - `instanceof` 夠聰明,可以知道實現介面的類別是該介面的實例,而不僅僅是該類別的實例。我認為頂部的說明沒有很清楚地說明這一點。
instanceof 運算子的簡單、乾淨、清晰的用法
首先,定義幾個簡單的 PHP 物件來操作 -- 我將介紹圓形和點。以下是兩者的類別定義
<?php
class Circle
{
protected $radius = 1.0;
/*
* 這個函式是我們會在下方使用 instanceof 運算子的原因。
*/
public function setRadius($r)
{
$this->radius = $r;
}
public function __toString()
{
return 'Circle [radius=' . $this->radius . ']';
}
}
class Point
{
protected $x = 0;
protected $y = 0;
/*
* 這個函式是我們會在下方使用 instanceof 運算子的原因。
*/
public function setLocation($x, $y)
{
$this->x = $x;
$this->y = $y;
}
public function __toString()
{
return 'Point [x=' . $this->x . ', y=' . $this->y . ']';
}
}
?>
現在,我們來實例化這些類別的幾個物件。注意,我會將它們放入一個陣列(集合)中,以便我們可以快速地迭代它們。
<?php
$myCollection = array(123, 'abc', 'Hello World!',
new Circle(), new Circle(), new Circle(),
new Point(), new Point(), new Point());
$i = 0;
foreach($myCollection as $item)
{
/*
* setRadius() 函式定義在上面的 Circle 類別中,
* 因此在呼叫它之前,請確保 $item 是 Circle 類別的實例,
* 以避免 PHP 出現 PMS(可能是指 PHP 錯誤訊息)!
*/
if($item instanceof Circle)
{
$item->setRadius($i);
}
/*
* setLocation() 函式定義在上面的 Point 類別中,
* 因此在呼叫它之前,請確保 $item 是 Point 類別的實例,
* 以免進急診室!
*/
if($item instanceof Point)
{
$item->setLocation($i, $i);
}
echo '$myCollection[' . $i++ . '] = ' . $item . '<br>';
}
?>
$myCollection[0] = 123
$myCollection[1] = abc
$myCollection[2] = Hello World!
$myCollection[3] = Circle [radius=3]
$myCollection[4] = Circle [radius=4]
$myCollection[5] = Circle [radius=5]
$myCollection[6] = Point [x=6, y=6]
$myCollection[7] = Point [x=7, y=7]
$myCollection[8] = Point [x=8, y=8]
您可以使用 "self" 來參考目前的類別
<?php
class myclass {
function mymethod($otherObject) {
if ($otherObject instanceof self) {
$otherObject->mymethod(null);
}
return 'works!';
}
}
$a = new myclass();
print $a->mymethod($a);
?>
如果您想使用 "$foo instanceof $bar" 來判斷兩個物件是否屬於同一個類別,請記住,如果 $foo 是 $bar 類別的「子類別」的實例,"instanceof" 也會評估為 true。
如果您真的想查看它們是否屬於「相同」的類別,那麼它們都必須是彼此類別的實例。也就是
<?php
($foo instanceof $bar && $bar instanceof $foo)
?>
可以將其視為 "get_class($bar) == get_class($foo)" 的替代方案,避免繞道進行字串查找和比較。
如果您想測試一個類別名稱是否為某個類別的實例,`instanceof` 運算子將無法運作。
<?php
$classname = 'MyClass';
if( $classname instanceof MyParentClass) echo 'Child of it';
else echo 'Not child of it';
?>
將永遠輸出
Not child of it
您必須使用 ReflectionClass
<?php
$classname = 'MyClass';
$myReflection = new ReflectionClass($classname);
if( $myReflection->isSubclassOf('MyParentClass')) echo 'Child of it';
else echo 'Not child of it';
?>
將輸出正確的結果。
如果您正在測試介面,請使用 `implementsInterface()` 而不是 `isSublassOf()`。
回覆 vinyanov at poczta dot onet dot pl
您提到「`instanceof` 運算子不接受字串作為其第一個運算元」。然而,這種行為是絕對正確的,因此,您誤導了實例的含義。
<?php 'ClassA' instanceof 'ClassB'; ?> 的意思是「名為 ClassA 的類別是名為 ClassB 的類別的實例」。這是一個無意義的句子,因為當您實例化一個類別時,您總是會得到一個物件。因此,您只能詢問一個物件是否為某個類別的實例。
我認為詢問「ClassA 是否屬於 ClassB」(或「ClassA 是 ClassB 類型的一個類別」)甚至「ClassA 也是 ClassB」更為合適。但第一種方法沒有被實作,而第二種方法只適用於物件,就像 `instanceof` 運算子一樣。
此外,我剛剛測試了您的程式碼,它與 `instanceof`(擴展到類別)的行為完全不同!我不建議任何人重複使用它。使用 <?php is_instance_of ($instanceOfA, 'ClassB'); ?> 在使用 `__autoload` 時會引發警告「include_once(Object id #1.php) …」(試圖將 `$instanceOfA` 當作類別名稱來尋找)。
最後,這裡有一個(對我來說)快速的範例函式程式碼,用於驗證物件或類別
<?php
function kind_of (&$object_or_class, $class)
{
return is_object ($object_or_class) ?
$object_or_class instanceof $class
: (is_subclass_of ($object_or_class, $class)
|| strtolower ($object_or_class) == strtolower ($class));
}
?> (在`is_subclass_of`中加入逗號)
PHP 解析器在這裡被註釋掉的兩行中的任何一行上都會產生解析錯誤。
顯然,`instanceof` 結構會在第二個位置接受一個字串變數,但它不會接受一個字串... 這很爛
class Bar {}
$b = new Bar;
$b_class = "Bar";
var_export($b instanceof Bar); // 這樣可以
var_export($b instanceof $b_class); // 這樣也可以
//var_export($f instanceof "Bar"); // 這樣語法上不合法
//var_export($f instanceof 'Bar'); // 這樣語法上不合法
使用未定義的變數會導致錯誤。
如果變數存在疑慮,必須先進行判斷
if ( isset( $MyInstance ) and $MyInstance instanceof MyClass ) ...
即使在 php4 中工作,這也是一個跨版本的函式
(instanceof 對於 php4 是一個未定義的運算子)
function isMemberOf($classename) {
$ver = floor(phpversion());
if($ver > 4) {
$instanceof = create_function ('$obj,$classname','return $obj instanceof $classname;');
return $instanceof($this,$classname);
} else {
// Php4 使用小寫類別名稱。
return is_a($this, strtolower($classname));
}
} // end function isMemberOf
請注意:!= 是一個獨立的運算子,具有獨立的語義。從語言文法的角度來看,否定一個運算子有點荒謬。當然,可以否定函式(例如 is_a())的結果,因為它並沒有否定函式本身或其語義。
instanceof 是一個二元運算子,因此像這樣用於二元項中
terma instanceof termb
而 !(否定)是一個一元運算子,因此可以應用於單個項,如下所示
!term
而一個項絕不會包含運算子,只有!。任何語言中都沒有這樣的結構(請指正!)。然而,instanceof 並沒有最終支援在每個運算元位置(上面的「terma」或「termb」)中巢狀項,就像否定那樣
!!!!!!!!!!!!!!term == term
所以回到原點,你曾經寫過
a !!!!!!!!!!!!= b
來測試等價性嗎?