如何在 PHP 中通过引用传递可变参数函数的参数? [英] How can arguments to variadic functions be passed by reference in PHP?

查看:73
本文介绍了如何在 PHP 中通过引用传递可变参数函数的参数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设有可能,如何通过引用可变参数函数传递参数而不在 PHP 中生成警告?我们不能再使用&"函数调用中的运算符,否则我会接受(即使它很容易出错,如果编码人员忘记它).

Assuming it's possible, how would one pass arguments by reference to a variadic function without generating a warning in PHP? We can no longer use the '&' operator in a function call, otherwise I'd accept that (even though it would be error prone, should a coder forget it).

这是我发现的旧 MySQLi 包装器类的灵感来源(这些天,我只使用 PDO).包装器和 MySQLi 类之间的唯一区别是包装器抛出异常而不是返回 FALSE.

What inspired this is are old MySQLi wrapper classes that I unearthed (these days, I'd just use PDO). The only difference between the wrappers and the MySQLi classes is the wrappers throw exceptions rather than returning FALSE.

class DBException extends RuntimeException {}
...
class MySQLi_throwing extends mysqli {
    ...
    function prepare($query) {
        $stmt = parent::prepare($query);
        if (!$stmt) {
            throw new DBException($this->error, $this->errno);
        }
        return new MySQLi_stmt_throwing($this, $query, $stmt);
    }
}
// I don't remember why I switched from extension to composition, but
// it shouldn't matter for this question.
class MySQLi_stmt_throwing /* extends MySQLi_stmt */ {
    protected $_link, $_query, $_delegate;

    public function __construct($link, $query, $prepared) {
        //parent::__construct($link, $query);
        $this->_link = $link;
        $this->_query = $query;
        $this->_delegate = $prepared;
    }
    function bind_param($name, &$var) {
        return $this->_delegate->bind_param($name, $var);
    }
    function __call($name, $args) {
        //$rslt = call_user_func_array(array($this, 'parent::' . $name), $args);
        $rslt = call_user_func_array(array($this->_delegate, $name), $args);
        if (False === $rslt) {
            throw new DBException($this->_link->error, $this->errno);
        }
        return $rslt;
    }
}

难点在于在包装器上调用诸如 bind_result 之类的方法.可以显式定义常量函数(例如 bind_param),允许传递引用.但是,bind_result 需要所有参数都通过引用传递.如果您按原样在 MySQLi_stmt_throwing 的实例上调用 bind_result,则参数按值传递并且不会进行绑定.

The difficulty lies in calling methods such as bind_result on the wrapper. Constant-arity functions (e.g. bind_param) can be explicitly defined, allowing for pass-by-reference. bind_result, however, needs all arguments to be pass-by-reference. If you call bind_result on an instance of MySQLi_stmt_throwing as-is, the arguments are passed by value and the binding won't take.

try {
    $id = Null;
    $stmt = $db->prepare('SELECT id FROM tbl WHERE ...');
    $stmt->execute()
    $stmt->bind_result($id);
    // $id is still null at this point
    ...
} catch (DBException $exc) {
   ...
}

由于上述类不再使用,所以这个问题只是一个好奇的问题.包装类的替代方法不相关.定义一个带有一堆参数的方法,采用 Null 默认值是不正确的(如果你定义了 20 个参数,但函数是用 21 调用的怎么办?).答案甚至不需要按照MySQL_stmt_throwing来写;它的存在只是为了提供一个具体的例子.

Since the above classes are no longer in use, this question is merely a matter of curiosity. Alternate approaches to the wrapper classes are not relevant. Defining a method with a bunch of arguments taking Null default values is not correct (what if you define 20 arguments, but the function is called with 21?). Answers don't even need to be written in terms of MySQL_stmt_throwing; it exists simply to provide a concrete example.

推荐答案

在 PHP 中没有通过引用传递可变长度参数列表的方法.这是语言的根本限制.

There is no way of passing variable length argument lists by reference in PHP. It is a fundamental limitation of the language.

但是,有一种使用 array(&$var1, &$var2...) 语法的解决方法:

There is, however, a workaround with array(&$var1, &$var2...) syntax:

<?php

/** raise all our arguments to the power of 2 */
function pow2() {
        $args = &func_get_arg(0);

        for ($i = 0; $i< count($args); ++$i) {
            $args[$i] **= 2;
        }
}


$x = 1; $y = 2; $z = 3;
pow2(array(&$x, &$y, &$z)); // this is the important line

echo "$x, $y, $z"; // output "1, 4, 9"

Test 也可以声明为 function test($args) 但我想说明这适用于 func_get_args() 系列职能.是 array(&$x) 导致变量通过引用传递,而不是函数签名.

Test could also be declared function test($args) but I wanted to illustrate that this works with the func_get_args() family of functions. It is the array(&$x) that causes the variable to be passed by reference, not the function signature.

来自对 PHP 函数参数文档的评论:http://php.net/manual/en/functions.arguments.php

From a comment on PHP's documentation on function arguments: http://php.net/manual/en/functions.arguments.php

这篇关于如何在 PHP 中通过引用传递可变参数函数的参数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆