使用动态参数计算平均值的简单函数
<?php
function average(){
return array_sum(func_get_args())/func_num_args();
}
print average(10, 15, 20, 25); // 17.5
?>
(PHP 4, PHP 5, PHP 7, PHP 8)
func_get_args — 返回包含函数参数列表的数组
获取函数的参数列表数组。
此函数可以与 func_get_arg() 和 func_num_args() 结合使用,以允许用户定义的函数接受可变长度的参数列表。
此函数没有参数。
返回一个数组,其中每个元素都是当前用户定义函数的参数列表中相应成员的副本。
如果从用户定义函数之外调用,则会生成警告。
示例 #1 func_get_args() 示例
<?php
function foo()
{
$numargs = func_num_args();
echo "参数数量: $numargs \n";
if ($numargs >= 2) {
echo "第二个参数是: " . func_get_arg(1) . "\n";
}
$arg_list = func_get_args();
for ($i = 0; $i < $numargs; $i++) {
echo "参数 $i 是: " . $arg_list[$i] . "\n";
}
}
foo(1, 2, 3);
?>
以上示例将输出
Number of arguments: 3 Second argument is: 2 Argument 0 is: 1 Argument 1 is: 2 Argument 2 is: 3
示例 #2 func_get_args() 按引用和按值传递参数的示例
<?php
function byVal($arg) {
echo '传递时 : ', var_export(func_get_args()), PHP_EOL;
$arg = 'baz';
echo '更改后 : ', var_export(func_get_args()), PHP_EOL;
}
function byRef(&$arg) {
echo '传递时 : ', var_export(func_get_args()), PHP_EOL;
$arg = 'baz';
echo '更改后 : ', var_export(func_get_args()), PHP_EOL;
}
$arg = 'bar';
byVal($arg);
byRef($arg);
?>
以上示例将输出
注意:
从 PHP 8.0.0 开始,func_*() 函数族旨在在命名参数方面基本透明,通过将参数视为全部按位置传递,并将缺失的参数替换为其默认值。此函数忽略未知命名可变参数的收集。只能通过可变参数访问收集的未知命名参数。
注意:
如果参数按引用传递,则对参数的任何更改都将反映在此函数返回的值中。从 PHP 7 开始,如果参数按值传递,则也将返回当前值。
注意: 此函数仅返回传递的参数的副本,而不考虑默认(未传递)参数。
...
语法使用动态参数计算平均值的简单函数
<?php
function average(){
return array_sum(func_get_args())/func_num_args();
}
print average(10, 15, 20, 25); // 17.5
?>
如果要按引用获取参数,则可以使用以下方法代替 func_get_args()
<?php
function args_byref(&...$args) {
// 在此处修改 $args 数组
}
?>
感谢 Markus Malkusch 在 Stackoverflow 上指出了这一点。
https://stackoverflow.com/a/29181826/1426064
如何创建一个多态/“重载”函数
<?php
function select()
{
$t = '';
$args = func_get_args();
foreach ($args as &$a) {
$t .= gettype($a) . '|';
$a = mysql_real_escape_string($a);
}
if ($t != '') {
$t = substr($t, 0, - 1);
}
$sql = '';
switch ($t) {
case 'integer':
// 根据ID搜索
$sql = "id = {$args[0]}";
break;
case 'string':
// 根据名称搜索
$sql = "name LIKE '%{$args[0]}%'";
break;
case 'string|integer':
// 根据名称和状态搜索
$sql = "name LIKE '%{$args[0]}%' AND status = {$args[1]}";
break;
case 'string|integer|integer':
// 根据名称和限制条件搜索
$sql = "name LIKE '%{$args[0]}%' LIMIT {$args[1]},{$args[2]}";
break;
default:
// :P
$sql = '1 = 2';
}
return mysql_query('SELECT * FROM table WHERE ' . $sql);
}
$res = select(29); // 根据ID搜索
$res = select('Anderson'); // 根据名称搜索
$res = select('Anderson', 1); // 根据名称和状态搜索
$res = select('Anderson', 0, 5); // 根据名称和限制条件搜索
?>
<?php
// 如何在PHP中模拟命名参数。
// 作者:Dave Benjamin <[email protected]>
// 将func_get_args()返回的数组转换为名称/值
// 对,以便extract()可以处理。
function varargs($args) {
$count = count($args);
for ($i = 0; $i < $count; $i += 2) {
$result[$args[$i]] = $args[$i + 1];
}
return $result;
}
// 示例
function test($ref1, $ref2) {
// 默认参数在此处。
$foo = "oof";
// 执行一些操作。
extract(varargs(func_get_args()));
echo nl2br("\n\$var1 = $var1");
echo nl2br("\n\$var2 = $var2");
echo nl2br("\n\$foo = $foo\n\n");
// 修改通过引用传递的一些变量。
// 请注意,func_get_args()不会传递引用,因此需要
// 在函数定义中显式声明它们。
$ref1 = 42;
$ref2 = 84;
}
$a = 5;
$b = 6;
echo nl2br("调用test()之前:\$a = $a\n");
echo nl2br("调用test()之前:\$b = $b\n");
// 尝试从以下行中删除'foo, "bar"'。
test($a, $b, var1, "abc", var2, "def", foo, "bar");
echo nl2br("调用test()之后:\$a = $a\n");
echo nl2br("调用test()之后:\$b = $b\n");
?>
合并func_get_args()和函数默认值
<?php
class utils {
/**
* @param 混合数组 $args
* @param ReflectionMethod $reflectionMethod
*
* @return array
*/
public static function mergeArgsWithDefaults( $args, \ReflectionMethod $reflectionMethod ) {
foreach ( array_slice( $reflectionMethod->getParameters(), count( $args ) ) as $param ) {
/**
* @var ReflectionParameter $param
*/
$args[] = $param->getDefaultValue();
}
return $args;
}
}
class sampleParent {
const USER_FILE_TYPE_FILE = 'FILE';
public function select( $idUserFile = null, $idUserFileType = self::USER_FILE_TYPE_FILE ) {
echo '[$idUserFile=>' . $idUserFile . ', $idUserFileType=>' . $idUserFileType, ']<br/>' . PHP_EOL;
}
}
class sample extends sampleParent {
const USER_FILE_TYPE_IMG = 'IMG';
public function select( $idUserFile = null, $idUserFileType = self::USER_FILE_TYPE_IMG ) {
return call_user_func_array( 'parent::select', \utils::mergeArgsWithDefaults( func_get_args(), new ReflectionMethod( __CLASS__, __FUNCTION__ ) ) );
}
}
$sample1 = new sampleParent();
$sample1->select();//打印 "" / self::USER_FILE_TYPE_FILE
$sample1->select(1);//打印 1 / self::USER_FILE_TYPE_FILE
$sample1->select(2, 'test 1');//打印 2 / "test 1"
echo '<br/>' . PHP_EOL;
$sample2 = new sample();
$sample2->select();//打印 "" / self::USER_FILE_TYPE_IMG
$sample2->select(3);//打印 3 / self::USER_FILE_TYPE_IMG
$sample2->select(4, 'test 2');//打印 4 / "test 2"
?>
请注意,可选参数不会被 func_get_args() 和 func_get_arg() 看到/传递。
例如
<?php
function testfunc($optional = 'this argument is optional..') {
$args = func_get_args();
var_dump($args);
echo $optional;
}
?>
测试用例 #1
testfunc('argument no longer optional..');
结果 #1
array(1) {
[0]=> string(20) "argument no longer optional.."
}
argument no longer optional..
测试用例 #2
testfunc('argument no longer optional..','this is an extra argument');
结果 #2
array(2) {
[0]=> string(29) "argument no longer optional.."
[1]=> string(25) "this is an extra argument"
}
argument no longer optional..
测试用例 #3: -- 结果为空数组
testfunc();
结果 #3
array(0) {
}
this argument is optional..
我想获得一个关联的参数列表,如果其他人也需要,我把它留在这里。
我希望 PHP 能原生支持这一点,因为核心实现会比这个用户空间回溯+反射实现更快。
<?php
/**
* 获取函数参数作为关联数组
* (与 func_get_args() 相同,但带有键)
*
* @param bool $populateMissingArgumentsWithDefaults 是否使用默认值填充缺失的参数
*
* @return array
*/
function func_get_args_associative(bool $populateMissingArgumentsWithDefaults = false): array
{
$trace = debug_backtrace(0, 2)[1];
$reflection = null;
if (isset($trace['class'])) {
$reflection = new \ReflectionMethod($trace['class'], $trace['function']);
} else {
$reflection = new \ReflectionFunction($trace['function']);
}
$ret = [];
foreach ($reflection->getParameters() as $param) {
if (array_key_exists($param->getPosition(), $trace['args'])) {
$ret[$param->name] = $trace['args'][$param->getPosition()];
} elseif ($populateMissingArgumentsWithDefaults) {
// 由于“在可选参数之后声明的必需参数隐式为必需”规则:
assert($param->isDefaultValueAvailable(), "我认为所有参数都在 trace[args] 中或具有默认值");
$ret[$param->name] = $param->getDefaultValue();
}
}
return $ret;
}
?>
例如,使用 count() 获取 func_get_args() 生成的数组的大小,不会考虑在函数定义中已分配默认值的形参。
示例
function foo($bar=true) {
echo count(func_get_args());
}
foo();
// 输出 0
foo("bar");
// 输出 1
当函数需要在没有值存在且 $bar 的值可能是 true、false、null 等时返回默认行为(无论该行为是什么)时,这是一个有用的测试条件。
看起来这个函数只返回一个副本并丢失了它的按引用信息,请改用这个非高效的变通方法。
在编写本文时,它目前将所有形参都作为引用返回,而不是只返回以这种方式传递的形参...
<?php
function func_get_args_byref() {
$trace = debug_backtrace();
return $trace[1]['args'];
}
?>
<?php
/*
此示例演示如何通过引用使用未知变量参数。
func_get_args() 不会通过引用返回参数,但
debug_backtrace() 的 "args" 是通过引用的。
在 PHP 5 中,这没有特别的意义,因为通过引用调用参数
已弃用并产生警告。
*/
class foo {
var $bar = "default bar";
function foo(/*可变参数*/) {
// func_get_args 返回参数的副本
// $args = func_get_args();
// debug_backtrace 返回参数的引用
$stack = debug_backtrace();
$args = array();
if (isset($stack[0]["args"]))
for($i=0; $i < count($stack[0]["args"]); $i++)
$args[$i] = & $stack[0]["args"][$i];
call_user_func_array(array(&$this, 'bar'), $args);
}
function bar($bar = NULL) {
if (isset($bar))
$this->bar = & $bar;
}
}
$global_bar = "bar global";
$foo = & new foo();
echo "foo->bar: ".$foo->bar."</br>\n";
$foo->bar = "new bar";
echo "global_bar: ".$global_bar."</br>\n";
/*
结果:
foo->bar: default bar</br>
global_bar: bar global</br>
*/
$foo = & new foo(&$global_bar);
echo "foo->bar: ".$foo->bar."</br>\n";
$foo->bar = "new bar";
echo "global_bar: ".$global_bar."</br>\n";
/*
结果:
foo->bar: bar global</br>
global_bar: new bar</br>
*/
?>
"因为此函数依赖于当前作用域来确定参数详细信息,所以它不能用作函数参数。如果必须传递此值,请将结果分配给一个变量,然后传递该变量。"
这意味着以下代码会产生错误
<?php
function foo($list)
{
echo implode(', ', $list);
}
function foo2()
{
foo(func_get_args());
}
foo2(1, 2, 3);
?>
但是,您可以通过执行以下操作轻松解决此问题
<?php
function foo($list)
{
echo implode(', ', $list);
}
function foo2()
{
foo($args = func_get_args());
}
foo2(1, 2, 3);
?>
这捕获了来自 foo2() 的上下文,使其合法。您将获得预期的输出
"1, 2, 3"