使用不同的参数调用PHP方法

时间:2011-09-21 19:27:35

标签: php api oop

我正在编写一个API类,我的总体目标是通过API可以轻松地访问任何类的方法,而无需对类本身进行任何重大更改。从本质上讲,我应该能够在我想要使用的任何类上实例化一个API类实例(在我的小框架内),并让它正常工作。

例如,在我的API类中,我有一个方法call,我想使用$_GET从我想要访问的类中调用正确的函数(让我们称之为{ {1}})。所以我在我的API中指定了一个Beep参数,因此action是调用action的方法,其中Beep中的其余参数可能是参数对于该方法。在$_GET中,我可以API->call,但我无法确定要从$ _GET发送哪些参数,以及发送它们的顺序。

$BeepInstance->$_GET['action']()将仅返回调用它的函数的给定参数列表,并且我不一定知道使用func_get_args传递它们的正确顺序。

有没有人试图做类似的事情?

3 个答案:

答案 0 :(得分:4)

这是一个解决方案+示例,它使用反射将输入参数映射到方法参数。我还添加了一种方法来控制暴露哪些方法以使其更安全。

class Dispatch {
    private $apis;

    public function registerAPI($api, $name, $exposedActions) {
        $this->apis[$name] = array(
            'api' => $api,
            'exposedActions' => $exposedActions
        );
    }

    public function handleRequest($apiName, $action, $arguments) {
        if (isset($this->apis[$apiName])) {
            $api = $this->apis[$apiName]['api'];
            // check that the action is exposed
            if (in_array($action, $this->apis[$apiName]['exposedActions'])) {
                // execute action

                // get method reflection & parameters
                $reflection = new ReflectionClass($api);
                $method = $reflection->getMethod($action);

                // map $arguments to $orderedArguments for the function
                $orderedArguments = array();

                foreach ($method->getParameters() as $parameter) {
                    if (array_key_exists($parameter->name, $arguments)) {
                        $orderedArguments[] = $arguments[$parameter->name];
                    } else if ($parameter->isOptional()) {
                        $orderedArguments[] = $parameter->getDefaultValue();
                    } else {
                        throw new InvalidArgumentException("Parameter {$parameter->name} is required");
                    }
                }

                // call method with ordered arguments
                return call_user_func_array(array($api, $action), $orderedArguments);
            } else {
                throw new InvalidArgumentException("Action {$action} is not exposed");
            }
        } else {
            throw new InvalidArgumentException("API {$apiName} is not registered");
        }
    }
}

class Beep {
    public function doBeep($tone = 15000)
    {
        echo 'beep at ' . $tone;
    }

    public function notExposedInAPI()
    {
        // do secret stuff
    }
}

示例:

// dispatch.php?api=beep&action=doBeep&tone=20000

$beep = new Beep();
$dispatch = new Dispatch();
$dispatch->registerAPI($beep, 'beep', array('doBeep'));

$dispatch->handleRequest($_GET['api'], $_GET['action'], $_GET);

答案 1 :(得分:1)

我们在API中做了类似的事情。我们使用代理方法_methodName($ p)并传入$ _GET或$ _REQUEST数组。代理方法知道实际方法所需参数的顺序,因此它正确地调用实际方法。使用call_user_func_array()可以很好地完成它。

不确定这是否是最好的方法,但它对我们来说效果很好。

控制器看起来像这样:

if (method_exists($server, "_$method"))
        $resp = call_user_func_array("{$server}::_$method", array($_REQUEST));

然后模型设置如下:

public function test($arg1, $arg2) { ... }
public function _test($p) {
    return $this->test($p['arg1'], $p['arg2']);
}

答案 2 :(得分:1)

我建议传递一个关联数组相应的方法。自从联想。 array为值映射提供了一个名称。

此外,从不做类似的事情:

  $BeepInstance->$_GET['action']()

这是非常不安全的。

可能定义另一个关联数组,它将作为GET'action'参数传递的动作映射到实际的方法名称。