The best option for calling model functionality in

2019-05-04 15:52发布

I am building a custom MVC framework using PHP. My problem is when I want to access any model class through the controller class. One way I have seen this done is through a registry design pattern using magic methods such as get and set, though PHP get and set are considered bad practise by some. I have read about dependency injection done through a container, but I can not see this working effectily as the container would have to call the models or it would have to contain the models which would defeat the purpose of MVC and create a massive super class. Singleton is seen as bad practise. Is there any solutions or improvements of the methods I have mentioned. It may just be my understand and knowledge of PHP needs improving.

Currently I have this: router.php (loads up controllor through a GET varible

 <?php

class router {



function __construct() {

    if (file_exists("controller/".$_GET['url']."Controller.php"))  {


       function __autoload($controller) {

           $controlinclude = "controller/".$controller.".php";
            include $controlinclude;

      }
       $control = $_GET['url']."Controller";
        new $control();


    }
    else    {

        // throw exception
    }

}

}
?>

Hope that makes sence

2条回答
三岁会撩人
2楼-- · 2019-05-04 16:34

A great Dependency Injection container is "pimple", which may be considered a service locator by some. It uses php 5.3's closures to create a class, that is used to create all of your project's objects through lazy loading. So, for instance, you can create a closure that contains the code for initializing a given object. You would then use the DI container's get() method, which would in turn, call the closure to create the object. Or simply pass you the object, if it has already been created.

// simplified dic class
class dic {

    protected $closures = array();
    protected $classes = array();

    public function addResource($name, Closure $initialization_closure) {
        $this->closures[$name] = $initialization_closure;
    }

    public function get($name) {
        if (isset($this->classes[$name]) === false) {
           $this->classes[$name] = $this->closures[$name]();
        }
        return $this->classes[$name];
    }
}

//setup
$dic = new dic();
$dic->addResource('user', function() {
   return new UserClass($some_args);
});
$dic->addResource('userContainer', function() use ($dic) {
   return new UserContainerClass($dic->get('user'));
});

// usage
$userContainer = $dic->get('userContainer');

This allows you to keep the flexibility of being able to change how and what objects get created throughout your project by only changing a very small amount of code.

查看更多
乱世女痞
3楼-- · 2019-05-04 16:38

First of all ... Do no put autoloading script in routing mechanism. You are mixing the responsibilities. You will be better off creating a separate class for this based on spl_autoload_register.

Neeext .. do no put complicated operations on constructor. It is makes you code somewhat untestable. Maybe you should be something like:

// you might want to replace $_GET with $_SERVER['QUERY_STRING'] later
$router = new Router( $_GET['url'] );

// where 'default' is the name of fallback controller
$controller_class = $router->get_controller( 'default' );
$method_name = $router->get_action( 'index' );

$model_factory = new ModelFactory( new PDO( ... ) );
$controller = new {$controller_class}( $model_factory );
$controller->{$method_name}();

Additionally, you should look into php namespaces. There is no point in ending class with ...Controller just to know where the class will be located.

Ok ... back to the Model.

There is quite common misconception about models in web development community ( i blame RoR for this mess ). Model in MVC is not a class, but an application layer which contains multitude of instances. Most of the instances belong to one of two types of classes. With following responsibilities:

  • Domain Logic :

    Deals with all the computation, calculation and all the domain specific details. Objects in this group have no knowledge of where and how data is actually stored. They only manipulate the information.

  • Data Access

    Usually made of objects that fit DataMapper pattern (do not confuse with ORM of same name .. nothing in common). Responsible for storing data from Domain Objects and retrieving them. Might be in database.. might not. This is where your SQL queries would be.

In semi-real world situation () it might looks something like this (related to code abowe):

class SomeController
{
   // ... snip ...
   protected $model_factory = null;
   // ... snip ...

   public function __construct( ModelFactory $factory )
   {
       $this->model_factory = $factory;
   }
   // ... snip ...

   public function action_foobar()
   {
      $user = $this->model_factory->build_object( 'User' );
      $mapper = $this->model_factory->build_mapper( 'User' );

      $user->set_id(42);
      $mapper->fetch($user);

      if ( $user->hasWarning()  )
      {
          $user->set_status( 'locked' );
      }

      $mapper->store( $user );
   }

   // ... snip ...
}

As you see, there is no indication how the data was stored. It does not even matter if user account was new, or already existing.

Some materials you might find useful

Videos

Books:

查看更多
登录 后发表回答