发布此内容是为了使“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)
要检查一个对象是否 *不是* 一个类的实例,可以使用 逻辑 not
运算符。
示例 #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() 函数。
发布此内容是为了使“typeof”一词出现在此页面上,以便在谷歌搜索“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
?>
我没有看到此页面上提到“命名空间”,所以我想我会插一句。当您将 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 类的一个_子类_的实例时也会返回真。
如果您真的想查看它们是否属于_同一个_类,那么它们必须都是对方类的实例。也就是说
<?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
来测试等价性?