【问题标题】:Making my own argument resolver for my my own PHP framework为我自己的 PHP 框架制作我自己的参数解析器
【发布时间】:2015-08-03 23:24:27
【问题描述】:

我决定制作我自己的小型 PHP 框架,我将在现实生活中使用它,为社交应用程序创建 Web 服务。

我开始阅读 Fabien Potencier 的指南,在 Symfony 的组件之上创建自己的框架 - http://symfony.com/doc/current/create_framework/index.html。 我真的很喜欢他的 classLoader 和 http-foundation 库,并决定集成它们。

我阅读了整个教程,但我决定停止集成 Symfony 的组件,直到教程的第 5 部分,他得到了 Symfony http 内核、路由匹配器和控制器解析器(不包括那些)。

我的框架的前端控制器和路由映射器文件有问题。

front.php(前端控制器)

<?php 

        require 'config/config.php';
        require 'config/routing.php';
        require 'src/autoloader.php';

        use Symfony\Component\HttpFoundation\Request;
        use Symfony\Component\HttpFoundation\Response;

        $request = Request::createFromGlobals();

        $response = new Response();


        $path = $request->getPathInfo();

        if(isset($siteMap[$path])) {
            call_user_func_array('src\Controllers' .'\\' . $siteMap[$path]['controller'] . '::' . $siteMap[$path]['action'], array($siteMap[$path]['arguments']));
        } else {    
            $response->setStatusCode('404');
            $response->setContent('Page not found');
        }

    $response->send();
?>  

我的路由文件:

/*  
    Map of routes
*/

$siteMap = array('/' => array('controller' => 'IndexController', 'action' => 'indexAction', 'arguments' => ''),
                    '/categories' => array('controller' => 'CategoriesController', 'action' => 'indexAction', '

我现在想知道的是,如果没有进一步使用 Symfony 的组件,我该怎么做这样的事情:

在我的路由文件中,我想添加一个 URL,如 '/hello' 和 Controller - Hello Controller 和参数名称、年龄、性别,这将对应于浏览器中的请求 GET www.base/hello/samuel/11/male .

在 HelloController 中有一个 indexAction($name, $age, $gender) { ... }。我曾尝试查看 Symfony 的源代码,但到目前为止我还没有发现(我花了很多时间查看库的源代码)。我将进一步模块化和分离前端控制器和控制器的功能,但我想把它弄下来。

啊,欢迎任何关于进一步构建我的框架的建议(我正在创建一个类似 REST 的框架 - 需要可扩展、快速并可能每秒处理数万个请求的 Web 服务)。

【问题讨论】:

    标签: php web-services rest symfony symfony-http-foundation


    【解决方案1】:

    您必须为您的路由定义正则表达式并将它们与请求相匹配,如果您想知道 Symfony 如何将其自己的路由格式(例如:'/path/to/{id}')转换为正则表达式,请参阅RouteCompiler: :编译模式。这超出了这个问题的范围,我不会提供任何代码。

    您的示例路由的正则表达式将类似于 ^/hello/(\w*)/(\d*)/(\w*)/$,这将匹配 '/hello/any string/any number/any string/' 例如:/hello/samuel/11/male(不要忘记 ^$,它们匹配字符串的开头和结尾)。

    您必须为每条路由提供一个正则表达式,并对所有路由执行preg_match(rawurldecode($request-&gt;getPathInfo(), $regex /* as created earlier*/, $matches)(直到一个匹配),而不是isset($sitemap[$path]),如果返回false,则路由不匹配。否则您必须得到控制器的参数如下:

    preg_match(rawurldecode($request->getPathInfo(), $regex /* as created earlier*/, $matches)
    $args = array();
    // we omit the first element of $matches, since it's the full string for the match
    for($i = 1; $i < count($matches); $i++){
      $args[] = $matches[$i];
    }
    

    现在您可以将$args 与默认参数合并并调用控制器。


    请参阅UrlMatcher::matchCollection(),了解 Symfony 如何将每个路由与正则表达式匹配,并构造参数。

    【讨论】:

    • 感谢您的详尽回答。正是我需要的!
    • 不客气。希望结果如你所愿。
    【解决方案2】:

    我想补充一些额外的信息。在 Symfony 中,您可以将请求的参数放入方法参数中:

    public function fooAction($bar);
    

    在这种情况下,它将在$request-&gt;attributes 中查找带有bar 的密钥。如果该值存在,它将将该值注入您的操作中。在 Symfony 3.0 及更低版本中,这是通过 ControllerResolver::getArguments() 完成的。从 Symfony 3.1 开始,您将能够实现或扩展 ArgumentResolver

    使用ArgumentResolver 意味着您可以轻松地将自己的功能添加到解析中。 The existing value resolvers are located here.

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-02-28
      • 1970-01-01
      • 2011-10-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-03-12
      相关资源
      最近更新 更多