【问题标题】:How do I implement controller action in a PHP MVC framework?如何在 PHP MVC 框架中实现控制器操作?
【发布时间】:2012-03-13 12:01:38
【问题描述】:

我正在尝试在 PHP 中创建自己的 MVC 框架来了解它们,但我目前无法实现控制器的操作。

问题在于,有些控制器有一个或多个参数,例如 actionView($id),而其他控制器没有参数,例如 actionCreate()。我该如何以不同的方式处理这些问题?

例如:

$action; //contains my action
$params; //array containing my arguments

在我的控制器中,我会调用...

$this->$action(); //for no parameters
$this->$action($params[0]); //for one parameter
$this->$action($params[0], $params[1]); //for two parameters
... and so on

像这样处理所有可能的情况是不可行的。也许我执行错误的操作。有人可以指导我正确的方向吗?

编辑:那里的 MVC 框架如何使处理多个参数成为可能?

【问题讨论】:

  • 您可以使用反射 (php.net/manual/en/reflectionfunctionabstract.getparameters.php) 来获取每个方法的参数。但是,由于我没有看到更多您的代码,我不确定您的 MVC 结构是什么样的。在我的框架中,我有一个调度程序,它使用call_user_func_array() 调度方法并将参数作为数组提供。
  • 前段时间我发现了this 关于设置 PHP MVC 的视频教程。到目前为止,它有 6 个部分,都留到下一个部分。所以你可以在任何你喜欢的地方停下来,仍然可以从中获得很多。 Imo,这是您所要求的非常好的教程。
  • 谢谢,我认为反射类正是我要找的,谢谢你的教程,我一定会去看看!

标签: php model-view-controller frameworks controller action


【解决方案1】:

我会简单地将参数数组作为每个动作的唯一参数传递。让大家知道您的框架的约定包括以这种方式将参数传递给操作。这允许实现代码选择他们想要如何处理它;使用func_get_args() 或者在方法签名中提供一个参数:

public function action(array $args = array()) { ...

需要注意的是,尽管您的操作可能需要一个参数,但用户实际上可能并未提供参数。如果您的方法签名设置为需要传递一个值并且您没有足够的值来插入,那么您可能会遇到各种错误。这是我选择简单地传入参数数组并始终传递一个数组的部分原因,即使它是空的。


或者,部分影响 BrNathanH 的答案,您可以以某种方式将对象绑定到给定的操作,然后将该数组注入对象的构造函数。该对象可以负责提供操作所需的数据并提供合适的默认值/检查值是否存在。然后,如果您想加倍确定他们正在获取适当的数据,您可以将对象签名添加到您的操作中。我不确定您将如何在自己的代码中实现这一点,主要问题是将 controller::action 映射到适当的“ParamObject”。但是将数组包装到对象中可能是一个好主意,并且可以解决不知道要传递多少参数的问题。它始终是一个,即与该操作关联的“ParamObject”。

【讨论】:

  • 您始终可以设置默认值,然后用传递的参数覆盖它们。这并不总是有效,但总比没有好。
  • @SurrealDreams 这是真的。最重要的是,您的所有参数都提供了默认值。我想这真的是个人喜好。写完答案后,我想我会在我自己的 MVC 宠物项目中实现“ParamObject”的想法。
  • 谢谢,我考虑过传入一个数组,但我喜欢正常写出方法头的想法,而不是为每个操作都有一个数组参数。
【解决方案2】:

我知道如何解释这一点的最佳方式是使用示例,因此这里是我自己的 PHP-MVC 应用程序实现示例。请务必密切注意 Hook::run 函数,该函数处理加载控件的参数。

index.php:

<?php
class Hook {
    const default_controller = 'home';
    const default_method = 'main';
    const system_dir = 'system/';

    static function control ($name, $method, $parameter) {
        self::req(Hook::system_dir.$name.'.php'); // Include the control file
        if (method_exists('Control', $method)) { // For my implementation, I can all control classes "Control" since we should only have one at a time
            if (method_exists('Control', 'autoload')) call_user_func(array('Control', 'autoload')); // This is extremely useful for having a function to execute everytime a particular control is loaded
            return call_user_func(array('Control', $method), $parameter); // Our page is actually a method
        }
        throw new NotFound($_GET['arg']); // Appear page.com/control/method does not exist, so give a 404
    }

    static function param ($str, $limit = NULL) { // Just a wrapper for a common explode function
        return (
            $limit
                ? explode('/', rtrim($str, '/'), $limit)
                : explode('/', rtrim($str, '/'))
            );
    }

    static function req ($path) { // Helper class to require/include a file
        if (is_readable($path)) return require_once($path); // Make sure it exists
        throw new NotFound($path); // Throw our 404 exeception if it doesn't
    }

    static function run() {
        list($name, $method, $parameter) = ( // This implementaion expects up to three arguements
            isset($_GET['arg'])
                ? self::param($_GET['arg'], 3) + array(self::default_controller, self::default_method, NULL) // + array allows to set for default params
                : array(self::default_controller, self::default_method, NULL) // simply use default params
        );
        return self::control($name, $method, $parameter); // Out control loader
    }

}

class AuthFail extends Exception {}
class UnexpectedError extends Exception {}
class NotFound extends Exception {}

try {
    Hook::run();
}
catch (AuthFail $exception) { // Makes it posssible to throw an exception when the user needs to login
    // Put login page here
    die('Auth failed');
}
catch (UnexpectedError $exception) { // Easy way out for error handling
    // Put error page here
    die('Error page');
}
catch (NotFound $exception) { // Throw when you can't load a control or give an appearance of 404
    die('404 not found');
}

系统/home.php:

<?php

class Control {
    private function __construct () {}
    static function autoload () { // Executed every time home is loaded
        echo "<pre>Home autoload\n";
    }
    static function main ($param='') { // This is our page
        // Extra parameters may be delimited with slashes
        echo "Home main, params: ".$param;
    }
    static function other ($param='') { // Another page
        echo "Home other, params:\n";
        $param = Hook::param($param);
        print_r($param);
    }
}

.htaccess:

RewriteEngine On

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l

RewriteRule ^(.+)$ index.php?arg=$1 [QSA,L]

通过这个 htaccess 文件,我们可以使用localhost/home/main 加载 home.php 控件。没有它,我们的网址看起来像localhost/index?args=home/main

演示截图1(localhost/simple_mvc/home/main/args1/args2/args3):

您并不总是知道特定的控制方法需要多少个参数,这就是为什么我认为最好传递一个由斜杠分隔的单个参数。如果控制方法需要多个参数,则可以使用提供的Hook::param 函数进行进一步评估。

演示截图2(localhost/simple_mvc/home/other/args1/args2/args3):

回答您的问题:
这里真正有助于回答您的问题的关键文件是.htaccess 文件,它将localhost/these/types/of/urls 透明地转换为localhost/index.php?args=these/types/of/urls 之类的东西。然后,您可以使用 explode($_GET['args'], '/'); 拆分参数。

here 是关于此主题的精彩视频教程。这真的有助于解释很多。

我对 home.php 和 index.php 进行了一些修改,并进行了最新的编辑

【讨论】:

  • 谢谢,这真的很有帮助。
  • 我已经对其进行了一些修改,查看这些更改可能会对您有所帮助。我已经修复了 Hook::param 函数的一个错误,它没有显示最后一个值,并且我修改了 Control::other 函数以更好地演示如何使用 Hook::param 将多个参数传递给控制函数.
【解决方案3】:

你可以只传递整个数组。问题是每个控制器都必须进行错误检查以查看是否存在正确的值。另一种解决方案是创建一个保存参数的数据对象。你有控制器访问它(它会为你做所有的错误检查)。

【讨论】:

    【解决方案4】:

    对于参数,您始终可以将一些参数设置为可选的。像这样:

    function($argument='', $argument2='')
    {
        // ...
    }
    

    这意味着$argument$argument2 是可选的。如果在调用函数时设置了这些参数...这些参数将具有值。

    虽然,传递array()(然后使用isset() 来检查设置的数组键或项)对于某些函数会更容易。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-12-31
      • 1970-01-01
      • 2016-06-23
      • 2013-04-16
      • 1970-01-01
      • 2012-05-20
      • 2017-05-10
      相关资源
      最近更新 更多