PHP 使用字符变量替换类名或方法名并调用方法
目的
想要通过字符变量来控制调用的 A 类或 B 类的方法,进而可以控制调用的对象。现实案例就是短信目前对接的是网易云信,想要再接入七牛云和阿里云的短信作为补充。
过程
一开始进入脑海就是:
$sms = 'Sms';
$sms::sendCode($mobile);
因为我记得之前看过这样使用的,但实际使用却会报错:Class 'Sms' not found
。之后再网上搜索 PHP 使用字符串调用类
相关的内容,发现大多的博文里都会提到一个 call_user_func
方法,类似的解是这样的:
call_user_func(array($class_name, 'doSomething'));
call_user_func($class_name .'::doSomething'); // >5.2.3
直接用类名和方法名替换,依然是不行的,还是提示找不到类。
找到 PHP 函数手册里 call_user_func
的定义,主要是看下面的使用案例。Example #3 call_user_func() using namespace name
里说明了使用命名空间的情况,看到这立马理解了问题所在。
$sms = __namespace__ . '\\' . 'Sms';
call_user_func(array($class_name, 'sendCode'), $mobile);
call_user_func($class_name .'::sendCode', $mobile); // >5.2.3
这是 Sms
类与当前类在同一命名空间的情况,其他情况可以修改 __namespace__
。
然后使用 new $className()
其实也是一样的:
$sms = __namespace__ . '\\' . 'Sms';
$sms_instance = new $sms();
$sms_instance::sendCode($mobile);
也是这里我意识到之前一直没有注意到问题:PHP 类的实例是可以调用静态方法的。这让我有点恍惚,我印象中静态方法只能通过类名::方法名方式调用,或者 self::
、static::
,难道是 java 或者 python 给我带来的错觉吗?不管了。
最后使用最开始的方法尝试,也是可以的:
$sms = __namespace__ . '\\' . 'Sms';
$sms::sendCode($mobile);
使用变量替换方法名:
# 直接替换
$sms = 'sendCode';
Sms::$sms($mobile);
# 使用 new 对象
$sms = __namespace__ . '\\' . 'Sms';
$sms_instance = new $sms();
$sms_instance->{'sendCode'}($mobile);
# 使用 call_user_func
call_user_func(array($sms, 'sendCode'), $mobile);