【问题标题】:How can I decouple $_POST/$_GET handling code from html forms/urls? (PHP-OOP)如何将 $_POST/$_GET 处理代码与 html 表单/url 分离? (PHP-OOP)
【发布时间】:2012-04-20 08:41:44
【问题描述】:

在一个类中,我有一个处理方法,它根据可用的 post/get 变量执行操作。这是一个简化的例子:

public function handleAll(array $vars) {
    if (isset($vars['var1'])) {
        $this->doThisAction($vars['var1']);
    } else if (isset($vars['var2'])) {
        $this->doAnotherAction($vars['var2']);
    }
}

所以在运行时可以像这样$handler->handleAll($_POST) 调用该方法。 问题是存储在 $vars 数组中的变量必须命名为“var1”和“var2”等。这意味着处理代码与 html 表单元素的名称或获取 url 中的变量(或者实际上是传入的任何数组)。

允许注入任何变量的数组使该方法具有灵活性,这是必要的,因为它也是多态的。类继承此方法并使用它来调用它自己的操作。其结果是,从外部看,处理方法需要什么才能发挥作用并不明显。这意味着必须检查实现以找出它的作用(除非我将代码复制到 phpdoc 中,这很愚蠢)。

我不确定如何解决这个问题。将大量的 if/case 语句全部暴露在索引页面上(来自多个这样的类)会导致代码非常混乱,因此最好将所有这些都封装在一个方法中。此外,将它作为类的方法来负责调用操作其自身状态的操作是有意义的(责任驱动设计)。我考虑过将每个变量作为方法的参数,但对于某些类,参数列表会非常大。这也意味着不能自动调用不同类的许多 handleAll() 方法,因为每次调用都需要显式注入所有参数,从而消除了多态方面。

总而言之,我需要保持方法的多态性,但我需要某种方式将处理代码与来自 html 表单或 url 的用户输入解耦。在这样做时,也许还有一种方法可以将接口与实现分开。我很惊讶我找不到任何解决方案,这似乎是一个常见问题。

【问题讨论】:

  • 不是让handleAll 处理所有事情,为什么不让个别方法处理他们期望的特定发布数据变量?
  • 如果我要为每个方法输入 post 变量,那么我会到处得到大量的 if/else 代码。此外,多态性将被删除,这意味着需要为每个类显式调用每个方法,这意味着不能在循环中进行许多对 handleAll() 的调用。如果我让每个方法都使用特定的 post 变量,因此无法注入依赖项,那么耦合问题仍然存在。
  • 你不能使用许多 MVC 框架之一吗?他们默认提供你想要的。基本上,您需要在控制器中“拆分”应用程序,每个控制器都有自己的责任。而 IMO 您目前拥有的方法绝不是多态的。它更像是一个前端控制器。
  • @MikeSW 我正在构建自己的。该方法是多态的,因为它是从超类型继承的,并且根据子类型其行为不同。实际上有一个前端控制器调用其他控制器(这反过来又可以调用其他控制器),想法是如果您封装一些控制代码,您可以避免一个巨大的长 ifelse/switch 语句。无论如何,这不是重点。这个问题与 MVC 无关,因为我的问题可能适用于任何类似的问题。

标签: php oop polymorphism encapsulation decoupling


【解决方案1】:

我不确定你所描述的是否可以避免。

如果您的代码需要特定的参数 - 无论是包含某些值的数组形式还是其他形式 - 该函数将始终依赖于正确填充的参数。

如果我有function foo($a, $b, $c),我总是需要填写参数。如果它们来自 POST,那么我需要从 POST 中获取它们。即使函数取而代之的是array('a' => ..., 'b' => ..., 'c' => ...),情况也是如此。

但是,如果您想将表单与参数列表分离,您可以使用一个简单的函数将 POST 数组转换为您的处理函数之一所期望的格式。不过,我真的看不出有什么原因,因为如果不需要,为什么还要增加额外的复杂性?

如果您希望更好地定义您的处理程序需要什么样的数组,您可以考虑让它需要一个对象。这种方法有时称为parameter object

使用参数对象的好处是您可以轻松地在构造函数中设置必需的参数,并为可选参数使用setter。任何使用您的代码的人都可以查看您对象的接口以了解需要哪些值。

如果您的处理程序使用的值实际上彼此相关,我会考虑创建一个实际的业务逻辑类型对象。使用 POST 中的数据创建它,并将处理值的代码移动到对象中的方法中。

【讨论】:

  • 这是一个很好的答案和一个很好的解决方案。唯一的问题是,您的建议本质上是目前班级的责任。它是一个控制器,它接受发布/获取信息,这些信息经过验证并转换为模型的对象(例如数据库表的 CRUD)。我将验证封装在控制器中,以便它可以输出有关正在发送的信息的反馈(例如,视图输出特定于问题的无效输入消息)。如果我将所有这些验证移至业务逻辑对象,您认为保留该功能的最佳方式是什么?
  • 是的,控制器将是与 POST 等耦合的部分,所以这是正确的。至于验证,如果你只需要在控制器中,你可以把它放在那里。如果您决定将其移至其他位置,您可以考虑创建一个验证对象的方法,并可能返回一个包含错误(如果有)或类似内容的数组。
  • 我已经有了业务逻辑对象,所以我会给它们另一个构造函数(返回 self 实例的静态方法),你可以在其中注入一个数组($_POST/$_GET/whatever)和其他参数可能是要查找的数组键。例如fromArr($_POST,'title','body')。您可以在具有不同数量参数的接口中定义方法吗?在 Java 中,我通常会超载。我想我会把handleAll重新定义为route($action, Item $item),但是继承路由的子类不能定义route($action, SpecificItem $item)。在 Java 中,我会使用泛型 Controller<SpecificItem>
【解决方案2】:

解耦和自动化处理方法,也可能是缩小范围的痛苦方法。但是除了为所有事物创建处理程序之外,没有太多选择。但是,我想添加一些东西。允许默认值并支持变化

function handlePOST() {    }
function handleGET()  {    }
function handleArr()  {    }

现在,这些函数可以代表它们保存函数的变体。

然而,在内部,除了编写所有处理程序之外,它们并不是更好的方法。但是 switch 是缩短它们并使用单独的函数进行处理。

switch($_POST['var1']) {
    case "value1": callPostValue1(); break;
    default: callPostDefaultHandler(); break;
}

【讨论】:

    猜你喜欢
    • 2011-05-06
    • 1970-01-01
    • 2012-01-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-28
    • 1970-01-01
    • 2019-12-15
    相关资源
    最近更新 更多