众所周知,当我们传少了参数到 PHP 函数的时候,会报 PHP Fatal error: Uncaught ArgumentCountError: Too few arguments to function xxx()
的错误,比如:
<?php
function hello($name)
{
echo "Hello, {$name}" . PHP_EOL;
}
hello();
// Fatal error: Uncaught ArgumentCountError: Too few arguments to function hello(), 0 passed in D:\tmp\hello.php on line 7 and exactly 1 expected in D:\tmp\hello.php:2
那如果我们将函数改写成下面这样呢?
<?php
function hello()
{
echo "Hello" . PHP_EOL;
}
hello("world");
// Hello
居然不会抛出 Too many arguments to function hello()
的错误!难道是 world
这个字符串被扔掉了而没有传进去?
将上面的函数再改一下:
<?php
function hello()
{
foreach (func_get_args() as $arg)
{
echo $arg . PHP_EOL;
}
}
hello("world");
hello("foo", "bar", "baz");
// world
// foo
// bar
// baz
全都已经传进去了呀!带着好奇心搜了一下,发现 StackOverflow 上已经有人问过这个问题了:
https://stackoverflow.com/que...
但是高票回答只是简简单单的一句话:
PHP doesn't throw an error on function overload.
然后还从评论区里翻到了这么一个 bug report:https://bugs.php.net/bug.php?...
官方给出的是 Wont fix
,(not a bug but a feature???)
除了上面两个链接之外,还找到了这个:
http://www.php-internals.com/...
但是看不太懂...
目前我能找到的资料就这些,很好奇但是又不是很清楚是怎么回事,先问几个问题:
- PHP 的函数参数最后是不是有个隐式的
可变长参数
?- PHP 的函数传参是怎么实现的?
- 像代码段 1,是不是其实正常传参的时候函数内部已经隐式使用
func_get_args()
帮我们把第一个参数值装到$name
里面去了?
然后再问一个问题:
像我这种没多少底层经验的新手,如果想阅读 PHP 的源码,该如何读起?把 php-internals
啃一遍会有帮助吗?
首先我来说明一下,关于
not a bug but a feature
的意思是不是bug,是PHP的新特性,PHP4,PHP5,PHP7都支持,具体可以看这篇文档 http://www.php.net/manual/zh/...。对于一个函数定义,假设如下:
在函数内部通过
func_get_args()
函数就可以取得传入的参数。也就是说,这本身就是PHP语法规则的一部分,假设调用PHP的函数或方法的时候传递的参数个数为N
,定义方法或函数的时候的参数个数为X
,则有 N >= X;另外,如果在定义方法或函数的时候对参数设置了默认值,则这个参数可以不传。既然说到这种是PHP本身语法规则的一部分,我这里告诉你一个PHP本身的函数就是通过这个原理实现的,那就是
compact
函数。举个例子
此时的
$d
为:在这种情况下就可以传无限个参数,然后如果根据这个参数判断存在以这个参数命名的变量,则把这个变量的值为数组的value,以参数名为数组的key进行打包,然后返回一个数组。