发布此内容是为了使“typeof”一词出现在此页面上,以便在您搜索“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)
要检查对象是否不是某个类的实例,可以使用 逻辑 非
运算符。
示例 #3 使用 instanceof
检查对象是否不是某个类的实例
<?php
class MyClass
{
}
$a = new MyClass;
var_dump(!($a instanceof stdClass));
?>
以上示例将输出
bool(true)
最后,instanceof
也可用于确定变量是否是实现 接口 的类的已实例化对象。
示例 #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() 函数的功能变体。
检查对象不是类的实例,示例 #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
?>
我没有在此页面上看到任何关于“命名空间”的提及,所以我认为我应该补充一下。当您将 instanceof 运算符作为字符串而不是简单的类名传递时,它将采用 FQCN 作为第二个运算符。即使您在顶层有 `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);
?>
## stdout ##
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 对象来处理——我将介绍 Circle 和 Point。这是两者的类定义
<?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 错误!
*/
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”来确定两个对象是否属于同一个类,请记住,“instanceof”在 $foo 是 $bar 类_子类_的实例时也会评估为 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));
}
?>
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
来测试等价性吗?