PHP __callStatic() 拿不到参数的情况
Posted 知其黑、受其白
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了PHP __callStatic() 拿不到参数的情况相关的知识,希望对你有一定的参考价值。
阅读目录
php 单例
单例模式的三个要点:
1 需要一个保存类的唯一实例的静态成员变量:private static $_instance;
。
2 构造函数和克隆函数必须声明为私有的,防止外部程序 new
类从而失去单例模式的意义;
3 必须提供一个访问这个实例的公共的静态方法,从而返回唯一实例的一个引用 。
<?php
class Demo
//静态变量私有化,防止类外修改
private static $_instance;
public $version;
//构造函数私有化,类外不能直接新建对象
private function __construct()
// self::$_instance = $this;
//在__clone前用private修饰,用来禁止克隆
private function __clone()
public function test($ver = 1)
$this->version = $ver;
// $new=true 时将传出一个新的实例
public static function instance($new = false)
if ($new)
return new self();
if (empty(self::$_instance))
self::$_instance = new self();
return self::$_instance;
// 由于 $this 指向的是当前对象, self 指向的是类, 因此 self::$_instance = $this; 会将之后的实例给覆盖掉
$ins1 = Demo::instance();
$ins1->test(3);
echo $ins1->version . PHP_EOL;
$ins3 = Demo::instance(true);
$ins3->test();
echo $ins3->version . PHP_EOL;
$ins2 = Demo::instance();
echo $ins2->version . PHP_EOL;
echo $ins2->version . PHP_EOL;
输出:
3
1
3
3
由于我当时的画蛇添足, 在构造函数里加了一行 self::$_instance = $this;
导致同样的代码输出却是:
3
1
1
1
后来想了想为什么, 回忆一下得出一个答案, 就是 $this和self
的区别:
$this 可以说是当前对象的标识符,self 是当前类的标识符。
self::$_instance = $this;
时, 代表着把当前对象覆盖到类的静态属性中,静态属性是和类一起共有同一片内存的,,那么当 ins3
里新生成对象的时候,把原有的类属性给覆盖掉了,因此之后再使用 Demo::instance()
时获得的对象就和 $ins3
之前的不一样了。
从这里看 static
这个关键词使用要慎重, 使用场景只有读的情况可以随意使用, 还能节省一点内存(毕竟每个对象查到的属性都是从同一片内存中读的), 但是涉及到 读写 的时候, 就要想明白它的运行顺序了。
php 的 __callStatic 函数
现在很多框架中调用方法都是Foo::bar()这种格式的,但是他们真的是静态方法吗?
larave 中尤其常见,但是开发过程中很明显这些有一部分不是静态的,比如你使用一个模型User,那么你每次实例化出来他都是一个全新的,互不影响,这里就用到了一个魔术方法__callStatic。
举个栗子:
<?php
class Test
public function __call($name, $arguments)
echo 'this is __call'. PHP_EOL;
public static function __callStatic($name, $arguments)
echo 'this is __callStatic:'. PHP_EOL;
$test = new Test();
$test->hello();
$test::hi();
//输出:this is __call:hello
//输出:this is __callStatic:hi
当然魔术方法也是很耗性能的一种方式,每次调用的时候后会先扫一遍 class 没找到方法时才会调用它,而为了代码的整洁和抽象这个方法也能给很大的帮助,在这之间去要有个权衡。
下面实现的 log 类,采用的就是这种方法,将方法解耦出来,只要符合规定的接口就能调用
<?php
class Test
//获取 logger 的实体
private static $logger;
public static function getLogger()
return self::$logger?: self::$logger = self::createLogger();
private static function createLogger()
return new Logger();
public static function setLogger(LoggerInterface $logger)
self::$logger = $logger;
public function __call($name, $arguments)
call_user_func_array([self::getLogger(),$name],$arguments);
public static function __callStatic($name, $arguments)
forward_static_call_array([self::getLogger(),$name],$arguments);
interface LoggerInterface
function info($message,array $content = []);
function alert($messge,array $content = []);
class Logger implements LoggerInterface
function info($message, array $content = [])
echo 'this is Log method info' . PHP_EOL;
var_dump($content);
function alert($messge, array $content = [])
echo 'this is Log method alert: '. $messge . PHP_EOL;
Test::info('喊个口号:',['好好','学习','天天','向上']);
$test = new Test();
$test->alert('hello');
PHP __callStatic() 拿不到参数的情况
<?php
class Test
// 实例
protected static $instance;
public static function make($rules = [], $message = [], $field = [])
/*
var_dump(self::$instance); null
var_dump($rules, $message, $field);
array(0)
array(0)
array(0)
*/
if (is_null(self::$instance))
self::$instance = new self($rules, $message, $field);
/*
var_dump($rules, $message, $field);
array(0)
array(0)
array(0)
*/
return self::$instance;
protected function is($value, $rule, $data = [])
var_dump($value, $rule, $data);
/*
int(555)
string(5) "email"
array(0)
*/
public static function __callStatic($method, $params)
/*
var_dump($method, $params);
array(2)
[0]=>
int(555)
[1]=>
string(5) "email"
*/
$class = self::make();
// var_dump(method_exists($class, $method)); true
if (method_exists($class, $method))
return call_user_func_array([$class, $method], $params);
else
throw new \\BadMethodCallException('method not exists:' . __CLASS__ . '->' . $method);
Test::is(555, 'email');
本地环境 php7.4.28
成功获取参数
array(2) [0]=> int(555) [1]=> string(5) "email"
生产环境 php 7.3.0
获取参数失败
array(2)
原因
PHP 7 ChangeLog 7.3.2
https://www.php.net/ChangeLog-7.php#7.3.2
Bug #77339 __callStatic may get incorrect arguments
https://bugs.php.net/bug.php?id=77339
call_user_func_array (内置函数)
call_user_func_array — 调用回调函数,并把一个数组参数作为回调函数的参数。
语法
call_user_func_array(callable $callback, array $args): mixed
把第一个参数作为回调函数(callback)调用,
把参数数组作(args)为回调函数的的参数传入。
参数
callback
被调用的回调函数。
args
要被传入回调函数的数组,这个数组得是索引数组。
函数调用方式
<?php
//单个参数
function LovePhper($app)
echo 'Love for - '.$app;
/方法名参数/// 方法内多个参数使用数组
call_user_func('LovePhper','PHP');
************************* 输出 *************************
Love for - PHP
//多个参数
function LikePhper(... $app)
$str = 'Like for - ';
foreach ($app as $key => $value)
echo $str,$value,PHP_EOL;
call_user_func_array('LikePhper', ['PHP','JAVA','Python','Dart'])
************************* 输出 *************************
Like for - PHP
Like for - JAVA
Like for - Python
Like for - Dart
调用类的内部方法
<?php
class Cladr
static function LovePhper($app)
echo 'Love for - '.$app;
call_user_func_array(array('Cladr','LovePhper'),['PHP'])
*************************输出*************************
Love for - PHP
命名空间使用
<?php
namespace Lj;
class Cladr
static function LovePhper($app)
echo 'Love for - namespace - '.$app;
call_user_func_array(array(__NAMESPACE__.'\\Cladr','LovePhper'),['PHP'])
*************************输出*************************
Love for - namespace - PHP
完整的函数作为回调传入 call_user_func_array()
<?php
$LovePhper = function($app)
return 'Love for - - '.$app;
;
echo call_user_func_array($LovePhper, ['PHP']);
*************************输出*************************
Love for - - PHP
以上是关于PHP __callStatic() 拿不到参数的情况的主要内容,如果未能解决你的问题,请参考以下文章
PHP中的__call和__callStatic方法(未看完)
php中__call() 和 __callStatic方法的使用
php中__call() 和 __callStatic方法的使用
PHP中的魔术方法总结 :__construct, __destruct , __call, __callStatic,__get, __set, __isset, __unset , __sleep