我将此Router.php作为我的应用程序的核心。
Router.php
<?php
final class Router
{
protected $routes = [];
protected $params = [];
public function add($route, $params = [])
{
$route = preg_replace('/\//', '\\/', $route);
$route = preg_replace('/\{([a-z]+)\}/', '(?P<\1>[a-z-]+)', $route);
$route = preg_replace('/\{([a-z]+):([^\}]+)\}/', '(?P<\1>\2)', $route);
$route = '/^' . $route . '$/i';
$this->routes[$route] = $params;
}
public function getRoutes()
{
return $this->routes;
}
public function match($url)
{
foreach ($this->routes as $route => $params) {
if (preg_match($route, $url, $matches)) {
foreach ($matches as $key => $match) {
if (is_string($key)) {
$params[$key] = $match;
}
}
$this->params = $params;
return true;
}
}
return false;
}
public function getParams()
{
return $this->params;
}
public function dispatch($url)
{
$url = $this->removeQueryStringVariables($url);
if ($this->match($url)) {
$controller = $this->params['controller'];
$controller = $this->convertToStudlyCaps($controller);
$controller = $this->getNamespace() . $controller;
if (class_exists($controller)) {
$controller_object = new $controller($this->params);
$action = $this->params['action'];
$action = $this->convertToCamelCase($action);
if (is_callable([$controller_object, $action])) {
$controller_object->$action();
} else {
echo "Method $action (in controller $controller) not found";
}
} else {
echo "Controller class $controller not found";
}
} else {
echo 'No route matched.';
}
}
protected function convertToStudlyCaps($string)
{
return str_replace(' ', '', ucwords(str_replace('-', ' ', $string)));
}
protected function convertToCamelCase($string)
{
return lcfirst($this->convertToStudlyCaps($string));
}
protected function removeQueryStringVariables($url)
{
if ($url != '') {
$parts = explode('&', $url, 2);
if (strpos($parts[0], '=') === false) {
$url = $parts[0];
} else {
$url = '';
}
}
return $url;
}
protected function getNamespace()
{
$namespace = 'catalog\controller\\';
if (array_key_exists('namespace', $this->params)) {
$namespace .= $this->params['namespace'] . '\\';
}
return $namespace;
}
}
为了实现对象的中央存储,我实现了这个注册表模式,它是结构的核心。
Registry.php
<?php
final class Registry
{
private $data = array();
public function get($key)
{
return (isset($this->data[$key]) ? $this->data[$key] : null);
}
public function set($key, $value)
{
$this->data[$key] = $value;
}
public function has($key)
{
return isset($this->data[$key]);
}
}
基本/核心控制器在其构造函数中还具有$ registry。
CoreController.php
<?php
abstract class CoreController
{
protected $registry;
public function __construct($registry)
{
$this->registry = $registry;
}
public function __get($key)
{
return $this->registry->get($key);
}
public function __set($key, $value)
{
$this->registry->set($key, $value);
}
}
CoreController被所有app控制器扩展为继承属性。
Posts.php
<?php
class Posts extends CoreController
{
public function index() {
echo 'Hello from the index action in the posts controller';
}
public function addNew() {
echo 'Hello from the addNew action in the posts controller';
}
public function edit() {
echo '<p>Route parameters: <pre>'.var_dump($this->registry).'</pre></p>';
}
}
要实例化注册表和路由器,这就是
中的内容的index.php
<?php
// Instantiate registry
$registry = new \system\core\Registry();
// Database
$db = new DB(DB_HOSTNAME, DB_USERNAME, DB_PASSWORD, DB_DATABASE);
$registry->set('db', $db);
$router = new \system\core\Router();
$registry->set('router', $router);
// Add the routes
$router->add('', ['controller'=>'HomeController', 'action'=>'index']);
$router->add('posts', ['controller'=>'posts', 'action'=>'index']);
//$router->add('posts/new', ['controller'=>'posts', 'action'=>'new']);
$router->add('{controller}/{action}');
$router->add('{controller}/{id:\d+}/{action}');
$router->add('admin/{controller}/{action}');
$router->dispatch($_SERVER['QUERY_STRING']);
在网址http://localhost/mvcsix/posts/1235/edit
后显示
这一切看起来都很好并且运作正常。
不知何故,这感觉不对。我var_dumped $ this-&gt;注册表,我有显示路由的参数,但我觉得要从路由获取参数我应该有var_dumped $ this-&gt; router-&gt; getParams()。当我var_dump $ this-&gt; router-&gt; getParams()时,我收到一条错误,上面写着
致命错误:在
中调用数组上的成员函数get()
我说这是因为我在注册表中也有数据库对象并且要显示查询我做$result = $this->db->query("SELECT * FROM members");
为什么我在$ this-&gt;注册表上显示参数而不在$ this-&gt; router-&gt; getParams(); ?
P.S。上面的代码是原始代码的删除。这个帖子还有一些名称空间和更多的东西。
答案 0 :(得分:4)
当注意到alex_edev
时,您正试图在数组上调用get
方法。但它来自哪里?
出了什么问题。
Posts
控制器在路由器的方法dispatch
中初始化。网址/posts/1235/edit
与第二条路线规则匹配,因此执行以下行
$controller_object = new $controller($this->params);
$action = $this->params['action'];
$action = $this->convertToCamelCase($action);
注意传递给控制器构造函数的内容。你传递路线params
属性!查看Posts.php
,Posts
控制器扩展CoreController
,因此它期望Registry
作为构造函数的参数,但是您传递了一个数组 - Route::params
属性。所以这是错误的对象结构,制动党。
为什么它能正常工作。
没有var_dump
,一切正常,因为您没有调用Posts::__get
方法。当您在$this->router->getParams()
控制器中调用Posts
时,它会尝试使用getter获取未定义的router
属性,并且由于错误的注册表而失败 - 请记住,您向控制器注入了一个数组。
应该做什么
你应该以这种方式启动控制器
$controller_object = new $controller($this->registry);
registry
注入__construct
:
final class Router
{
// add definition
private $registry;
// pass it to the router
public function __construct($registry) {
$this->registry = $registry;
}
....
}
路由器启动如下
$registry->set('db', $db);
$router = new \system\core\Router($registry);
因此,您只需要编辑6行代码。
P.S。使用Type declarations可以避免此类错误。如果您编写public function __construct(Registry $registry)
php,则在传递数组时抛出TypeError
异常。
答案 1 :(得分:2)
您在此处发布的代码无法进行测试,因为它缺少HomeController
类定义,而且调用var_dump(...)
的位置和时间也不太明确。但是我已经尝试根据您提到的致命错误猜测您的问题,并在var_dump()
课程的edit()
函数中致电Posts
。看起来您试图从该函数转储$this->router->getParams()
。
&#34;致命错误:在&#34;中的数组上调用成员函数get()表示您尝试在$arr->get()
上调用$arr
,这是一个数组(不是对象)。您可以在CoreController的类getter中调用此类get()
函数。并且该调用是由$registry
属性的范围构成的,因此应该具有Object类型。
因此,在这种情况下,您应该在尝试转储protected $registry
之前检查$this->router->getParams()
的类型。这可能不是你所期望的那样。
我没有找到你在代码中实例化Posts
类对象的地方,以及你在$registry
__constructor()
中放置的对象<%= form_for(@user, url: signup_path) do |f| %>
<%= render 'shared/error_messages' %>
<%= f.text_field :name, class: "login", placeholder: :name
...more fields...
<%= f.check_box :agreement, class: "field login-checkbox" %>
<label class="choice" for="Field"><%= t("agree_terms") %></label>
<%= f.submit t("register"), class: "button btn btn-primary btn-large" %>
<% end %>
所以我可以不检查我的猜测。如果你澄清这一点,那么找到问题会更容易。