Php 在MVC中,如何将总是使用的属性从控制器传递给其他类?

Php 在MVC中,如何将总是使用的属性从控制器传递给其他类?,php,class,model,controller,Php,Class,Model,Controller,我目前正在改进自己的MVC,对于以下场景,我找不到一个好的解决方案: 在我的大多数模型中,我使用的是一些(已经被另一个模型验证过的)基于用户的输入,当然需要将它们从控制器(我基本上告诉模型如何处理输入)传递到各种模型。目前,我正在将每个用户输入放入一个属性: foreach($this->properties as $property => $empty) { if(isset($_POST[$property])) {

我目前正在改进自己的MVC,对于以下场景,我找不到一个好的解决方案: 在我的大多数模型中,我使用的是一些(已经被另一个模型验证过的)基于用户的输入,当然需要将它们从控制器(我基本上告诉模型如何处理输入)传递到各种模型。目前,我正在将每个用户输入放入一个属性:

    foreach($this->properties as $property => $empty)
    {
        if(isset($_POST[$property]))
        {
            $this->properties[$property] = htmlspecialchars(trim($_POST[$property]));
        }
    }
class baseController
{
    protected $userProperties;
    public function __construct()
    {
        $this->userProperties = Request::getInstance()->getUserProperties();
    }
}
最终,当我需要一个新的模型来做某事时,我这样称呼它:

    new view('calendar',$data,$this->properties);
最后,在模型中,我通过将输入/变量放入模型属性中来接收它们

class validation
{   

    public function __construct($values)
    {
        foreach($values as $property => $value)
        {
            $this->{$property} = $value;
        }
    }
}
这样,我就不必考虑变量来自何处(在用户输入经过验证之后,我真的不在乎了),并且可以随时为我编写一个干净易读的
$this->user\u input版本

但我有一种感觉,这不是最简单的方法,也可能不是一种好方法。最让我烦恼的是,在编写新类/模型时,我总是必须告诉模型将输入带入它们自己的属性,并且在调用新类时,我总是必须传递参数

当调用一个新类时,我是否可以通过某种方式从用户那里继承这些变量,而无需将控制器设置为父类?或者,将控制器设置为父类是否有意义?我认为,当另一个控制器使用该模型时,会令人困惑

将控制器设置为父控制器是否有意义


是的,我可能就是这么做的。然后,您可以对要共享/继承的属性使用protected。

根据您的需要,将用户输入存储在(例如UserRequest类)的属性中可能是有意义的:

在引导类或路由类中,捕获用户输入时,将其保存在请求实例中,然后让所有控制器扩展读取此属性的基类:

    foreach($this->properties as $property => $empty)
    {
        if(isset($_POST[$property]))
        {
            $this->properties[$property] = htmlspecialchars(trim($_POST[$property]));
        }
    }
class baseController
{
    protected $userProperties;
    public function __construct()
    {
        $this->userProperties = Request::getInstance()->getUserProperties();
    }
}

然后所有控制器都可以访问它,您只需捕获一次

我认为更好的解决方案是将所有输入存储在一个对象中,让我们称之为
data
。每个模型都可以具有
数据
属性。控制器完成输入验证后,可以将对象传递到第一个模型并存储在那里。此时,可以在模型之间自由传递对象。如果要更改
data
中的值,则应稍后使用方法调用更新controllers对象,如
$this->data=$Model->GetData()或其他什么

在MVC范例中,让模型访问控制器的属性是不明智的。控制器基本上应该启动所有通信,即控制器将数据传递给对其进行操作的模型,然后控制器请求该数据并将其放入视图中。让控制器直接保存数据和在其上运行的模型不是一个好的做法

最让我烦恼的是,在编写新类/模型时,我总是必须告诉模型将输入带入它们自己的属性,并且在调用新类时,我总是必须传递参数

假设你有两个问题:

  • 重复定义每个类定义的属性
  • 为每个类创建传递参数
  • 从最简单和最基本的意义上讲,你不能回避这两个问题。如果您不告诉类(至少不知何故)它表示哪些属性,它就不会知道。第二点有点类似,如果数据没有设置为类,它将无法工作

    因此,从技术上讲,根本不可能防止这两种情况的发生,问题是如何让它变得更舒适,并减少重复——如果可能的话

    一种方法是将所有这些对象都设置为同一类型。我的意思是,实际上这些只是一些改进的阵列,不是吗

    因此,您可以自己创建一个基类,可以从中进行扩展,该基类包含所有需要的代码,例如导入数组、定义属性

    因此,您只需要编写一次代码,并创建任意数量的对象和不同的“类型”

    举个例子,让我们创建一个这样的对象,它有一个基类来完成它的工作:

    class TestModel extends SelfDefinedVariableObjectBase
    {
        protected $properties = ['bar' => 'hello world'];
    }
    
    就是这样,对象定义。现在让我们使用它:

    // $_POST['bar'] = '<h1>test</h1> let\'s throw some HTML in';
    
    $foo = new TestModel($_POST);
    echo $foo->bar, "\n";
    
    你现在可能想要这个。因此,您可以创建一些装饰器,例如,这里的装饰器使用回调函数:

    class VariableObjectCallbackDecorator
    {
        private $subject;
        private $callback;
    
        public function __construct(VariableObjectBase $object, callable $callback) {
            $this->subject = $object;
            $this->callback = $callback;
        }
        public function __get($name) {
            return call_user_func($this->callback, $this->subject->__get($name));
        }
    }
    
    让我们将其用于上一个示例中的测试对象:

    $bar = new VariableObjectCallbackDecorator($foo, 'htmlspecialchars');
    echo $bar->bar, "\n";
    
    现在这一次的输出是:

    &lt;h1&gt;test&lt;/h1&gt; let's throw some HTML in
    

    希望这是有帮助的。您可以在这里找到代码:

    好的,这里要记住的一件大事是,您的控制器“有一个”变量容器(保存所有属性),而控制器是(或“是一个”)变量容器。所以首先,您应该使用组合,而不是继承

    下面的代码片段将被注释以更详细地解释。一些注意事项:

    • InputData实例可以创建在控制器级别之上(例如,在不同的控制器中,以便可以在多个控制器之间共享),这回答了问题的主要部分。关键的一点是你只写了一次,你可以放心地说,一旦它在那里,它的好去

    • 您可以在InputData中包含所有验证方法,因为InputData的作用是安全地存放/存储数据——在我看来,这是一个良好的abtraction级别,或者换句话说,“它负责输入数据,如果输入数据有问题,我知道该去哪里查找”

    • 最后,为了增加一些额外的亮点,我添加了一些位操作,以便在通过input_data->add添加值时,可以针对多种类型对它们进行验证(例如,可以添加一些需要同时验证为数字和
      require_once( "Controller.php" );
      
      $controller = new Controller();
      $controller->print_current_user();
      
      <?
      require_once( "Input_Data.php" );
      
      class Controller 
      {
          // Variables    
          private $input_data;
      
          // Models
          // private $model_user;
      
          public function __construct() 
          {
              $this->input_data = new Input_Data();
              //$this->model_user = new Model_User();
      
              // Process input (might not happen in the constructor,
              // in fact, it might happen higher up, so it can be shared
      
              // Possibly looping over GET / POST data
              // for each one, add it to the inputData
              $_GET[ 'name' ] = 'Chris';
              $_GET[ 'country' ] = 'Australia';        
      
              // example iteration 1        
              $this->input_data->add( 'name', $_GET[ 'name' ], Input_Data::TYPE_VALIDATE_NAME | Input_Data::TYPE_VALIDATE_TEXT );
              // example iteration 2
              $this->input_data->add( 'country', $_GET[ 'country' ], Input_Data::TYPE_VALIDATE_COUNTRY );
          }
      
          // later on in controller, model needs to find the user by name
          public function print_current_user() 
          {
              // Example Usage to Model:
              // $this->$model_user->get_by_name( $this->input_data->get( 'name' ) );
              //
              // For now, we'll settle with just printing it out
              echo $this->input_data->get( 'name' );
          }
      }
      ?>
      
      <?
      class Input_Data 
      {
          const TYPE_VALIDATE_TEXT = 0;
          const TYPE_VALIDATE_NAME = 1;
          const TYPE_VALIDATE_EMAIL = 2;
          const TYPE_VALIDATE_ADDRESS = 4;
          const TYPE_VALIDATE_COUNTRY = 8;
      
          protected $data;
      
          public function __construct() {
              $this->data = array();
          }
      
          public function add( $name, $value, $type )
          {
              if( $type & TYPE_VALIDATE_TEXT )        
              {
                  // validate input as text
                  // if valid, flag as such, to be inserted
                  // or alternatively return a safe version
                  // depending on your application, an empty string
              }    
              if( $type & TYPE_VALIDATE_NAME )        
              {
                  // validate input as name
              }
              if( $type & TYPE_VALIDATE_EMAIL )        
              {
                  // validate input as email
              }    
              if( $type & TYPE_VALIDATE_ADDRESS )        
              {
                  // validate input as address
              }    
              if( $type & TYPE_VALIDATE_COUNTRY )        
              {
                  // validate input as country
              }    
      
              // If its valid or is now santised
              // insert into the $data variable
              // if( $valid ) {
              $this->data[ $name ] = $value;
              // }
              // data[ name ] now contains a safe value that can be accessed
          }
      
          public function get( $name )
          {
              // do checking to ensure it exists
              // then return it
              return $this->data[ $name ];
          }
      }
      ?>