学习PHP中的类相关函数
今天我们学习的内容主要是和类、对象有关的一些数据函数。也就是以获取类、对象的信息属性为主的一些函数。这些函数本身比较简单,在日常的业务开发中,或者说很多框架的实现中都能见到它们的身影,但真正我们自己使用的场景还是不多,大家以了解为主。
类别名
首先是类的别名。就像 Linux 中的 alias 一样,为 PHP 中的类也创建一个别名,可以通过这个别名来实例化对象。
class foo {}
class_alias('foo', 'baz');
$a = new foo();
$b = new baz();
var_dump($a == $b); // bool(true)
var_dump($a === $b); // bool(false)
var_dump($a instanceof baz); // bool(true)
var_dump($b instanceof foo); // bool(true)
使用 class_alias() 函数就可以实现指定一个类的别名。通过指定别名之后,我们可以看到,原始的类实例化的对象和别名实例化的对象在全等情况下会返回 false ,而在其它情况下,它们都是一样的。甚至于使用 instanceof 互相判断他们都会返回 true 。这里我们需要注意的是,全等情况下两个类实例不相同意味着他们并不是完全相等的两个实例,毕竟两个实例都是 new 出来的,即使是同一个类的实例对象也不是全等的,他们的类 ID 号也是不同的。所以,在这里,我们可以将别名类看作是和原始类完全相同的(类是完全一样的模板)。
判断类、接口、特性是否存在
这个主要是在当前运行环境下的 PHP 脚本中,是否存在指定的类、接口或者特性。
var_dump(class_exists('MyClass')); // bool(false)
var_dump(class_exists('foo')); // bool(true)
interface Ifoo{}
var_dump(interface_exists('MyInterface')); // bool(false)
var_dump(interface_exists('Ifoo')); // bool(true)
trait Tfoo{}
var_dump(trait_exists('MyTrait')); // bool(false)
var_dump(trait_exists('Tfoo')); // bool(true)
如果全局都没有定义相应的类、接口、特性的话,那么对应的函数就会返回 false 。
检查类中的方法、属性是否存在
上面的函数指的类、接口、特性是否被定义,是否在运行的 PHP 中存在,而我们接下来看到的是检测一个类中指定的方法、属性是否存在。
class con{
private $b;
protected $b1 = 'b1';
public $b2 = 'b2';
public function c(){
}
protected function d(){
}
private function e(){
}
function getClassName(){
echo get_class(), PHP_EOL;
}
static function getStaticClassName(){
echo 'get_class: ', get_class(), PHP_EOL;
echo 'get_called_class: ', get_called_class(), PHP_EOL;
}
}
$con = new con();
var_dump(method_exists($con, 'c')); // bool(true)
var_dump(method_exists('con', 'c')); // bool(true)
var_dump(method_exists('con', 'cc')); // bool(false)
var_dump(property_exists($con, 'b')); // bool(true)
var_dump(property_exists($con, 'bb')); // bool(false)
可以看到,在类相关的属性中,检测是否存在都是 xxx_exists() 相关的函数。而 method_exists() 和 property_exists() 都是针对单个类或者实例的。代码中我们分别使用类名(字符串)和实例对象的形式进行判断。
获取对象或类的一些属性
关于属性并不是说的类中我们自己定义的属性,而是关于这个类或对象本身自带的一些属性信息。我们一个一个地来看一看。
获取类名
ar_dump(get_class($a)); // string(3) "foo"
var_dump(get_class($b)); // string(3) "foo"
var_dump(get_class($con)); // string(3) "con"
$con->getClassName(); // con
使用 get_class() 方法可以获得对象的类名称。如果这个方法是在类的内部方法中使用的,那么可以不用传递参数,它直接返回的就是当前这个类的名称。比如我们的这个 getClassName() 方法,就是上一段代码中 con 这个类模板中定义的方法,里面直接打印了 get_class() 方法。
get_class() 方法的参数可以不填,如果填的话必须是一个实例对象,直接使用类名的话将会报警告信息并返回 false 。
var_dump(get_class('a')); // Warning: get_class() expects parameter 1 to be object, string given in
// bool(false)
获取类和对象的所有属性数组
获取类和对象的所有属性数组的意思其实就是将类中的我们定义的所有公开属性转换成一个数组。
var_dump(get_class_vars('con'));
// array(1) {
// ["b2"]=>
// string(2) "b2"
// }
var_dump(get_object_vars($con));
// array(1) {
// ["b2"]=>
// string(2) "b2"
// }
$con->newp = 'newp';
var_dump(get_object_vars($con));
// array(2) {
// ["b2"]=>
// string(2) "b2"
// ["newp"]=>
// string(4) "newp"
// }
get_object_vars() 这个方法的参数是可以接收类或者实例对象的,并且它获取的只能是类中的公开属性,也就是 public 的内容。
获取类的所有方法数组
和上面的属性数组类似,只不过这里是将类中的所有方法名放到一个数组中。
var_dump(get_class_methods('con'));
// array(2) {
// [0]=>
// string(1) "c"
// [1]=>
// string(12) "getClassName"
// }
同样的,get_class_methods() 方法也只能获取公开的方法名称。对于私有和静态方法都是无法获取到的。
获取后期静态绑定的类名称
还记得我们很早前讲过的后期静态绑定相关的知识吗?不记得的小伙伴可以回去再看一下 后期静态绑定在PHP中的使用https://mp.weixin.qq.com/s/N0rlafUCBFf3kZlRy5btYA 。在这里的这个函数主要就是用于返回静态方法中关于类名信息内容的。
con::getStaticClassName();
// get_class: con
// get_called_class: con
class con_child extends con{}
con_child::getStaticClassName();
// get_class: con
// get_called_class: con_child
其实这个 get_called_class() 方法和 get_class() 方法是类似的,都是返回类的名称的。只是 get_called_class() 在对于静态调用的时候会有特殊的处理,保证返回的类名是与后期静态绑定对应的类名。
获取对象或类的父类名
这个就不用多做解释了,就是获取指定类的父类的类名。
echo get_parent_class($con), PHP_EOL; //
echo get_parent_class('con_child'), PHP_EOL; // con
获取所有已定义的类、接口、特性
获取在当前运行环境中的所有类、接口和特性的信息,返回的就是数组。
var_dump(get_declared_classes());
// array(160) {
// [0]=>
// string(8) "stdClass"
// [1]=>
// string(9) "Exception"
// [2]=>
// string(14) "ErrorException"
// [3]=>
// ……………………
// ……………………
// ……………………
// [156]=>
// string(3) "foo"
// [157]=>
// string(3) "con"
// [158]=>
// string(9) "con_child"
// [159]=>
// string(3) "baz"
// }
var_dump(get_declared_interfaces());
// array(19) {
// [0]=>
// string(11) "Traversable"
// [1]=>
// string(17) "IteratorAggregate"
// [2]=>
// string(8) "Iterator"
// [3]=>
// string(11) "ArrayAccess"
// [4]=>
// string(12) "Serializable"
// [5]=>
// string(9) "Countable"
// ……………………
// ……………………
// ……………………
// [17]=>
// string(9) "Reflector"
// [18]=>
// string(4) "Ifoo"
// }
var_dump(get_declared_traits());
// array(1) {
// [0]=>
// string(4) "Tfoo"
// }
get_declared_classes() 和 get_declared_interfaces() 都会返回整个 PHP 环境下的所有类、接口信息。这些信息包括系统已经定义好的默认类和接口,也包括我们自己定义的类和接口。而 get_declared_traits() 中,只有我们自己定义的特性,这也说明,在 PHP 的默认环境中,是没有系统特性定义的。
判断对象是否属于类或是某个类的子类
最后我们来看一下如何判断一个类是否属于某个类或者是某个类的子类的函数。
var_dump(is_a($con, 'con')); // bool(true)
var_dump(is_a(new con_child, 'con')); // bool(true)
var_dump(is_a($con, 'foo')); // bool(false)
看到这个函数相信不少同学马上就会想到 intanceof 这个操作符。注意,is_a() 是一个函数,而 instanceof 是一个操作符,这两个不是一个概念哦。就像 echo 其实是一个操作符,虽然它可以写成 echo() 这样的形式,但它和 print() 是不同的两个东西。
// var_dump($con instanceof 'con'); // Parse error: syntax error, unexpected ''con'' (T_CONSTANT_ENCAPSED_STRING)
$conClassName = 'con';
var_dump($con instanceof con); // bool(true)
var_dump($con instanceof $conClassName); // bool(true)
instanceof 是不能写成字符串类名这种形式的,只能是直接放上类名或者是对象实例。这也是 instanceof 和 is_a() 最大的区别,在其它方面,可以看作这两个是相同的功能的操作。
var_dump(is_subclass_of($con, 'con')); // bool(false)
var_dump(is_subclass_of(new con_child, 'con')); // bool(true)
var_dump(is_subclass_of('con_child', 'con')); // bool(false)
is_subclass_of() 用于判断指定的类名、对象是否是某个类的子类。这个也比较简单,就不多说了。
总结
类相关的函数就是这些,当然,还有一些函数是放在 SPL 扩展库中的,比如我们在 PHP的SPL扩展库(四)函数https://mp.weixin.qq.com/s/lGB2DdDpVqWM7bsEy6wAMg 中学习过的 class_implements()、class_parents() 和 class_uses() ,分别就是返回的类中实现的接口、继承的类以及类中使用的特性,这些方法其实和 get_class_methods() 和 get_class_vars() 是比较像的。但是它们是 SPL 扩展中提供的功能。不过 SPL 已经默认集成在 PHP 源代码中了,所以也可以将它们看作是 PHP 默认提供的类相关函数。
测试代码:
https://github.com/zhangyue0503/dev-blog/blob/master/php/2021/04/source/5.%E5%AD%A6%E4%B9%A0PHP%E4%B8%AD%E7%9A%84%E7%B1%BB%E7%9B%B8%E5%85%B3%E5%87%BD%E6%95%B0.php
参考文档:
https://www.php.net/manual/zh/book.classobj.php