30/09/2018, 18:28

[PHP] xin ý tưởng xử lý route php

Mình đang viết code xử lý route. Mình muốn nó gioongs như laravel hay một framework khác theo kiểu:
1 route người dụng định nghĩa như /article/{id}/name. Thì trên url trình duyệt sẽ có dạng /article/11/name. Rồi lấy biến id thì được số 11. Mọi người có thể cho mình ý kiến về xử lý kiểu này không? Mình không biết so sánh 2 cái route đấy như thế nào. Cảm ơn mọi người!

asdasdasd viết 20:38 ngày 30/09/2018

Giải thích rõ hơn bạn ơi .

kid1412 viết 20:44 ngày 30/09/2018

Mình có 1 file route để định nghĩa ví dụ: /article/{id} thì trên trình duyệt sẽ chấp nhận mọi url có định nghĩa như trên nhưng cái biên id đó có thể là 1 cái gì đó bất kì mà mình chỉ cần lấy biêns id thì sẽ in ra được gía trị. VD: /article/1234 thì gía trị sẽ là 1234

Đinh Quốc Hân viết 20:37 ngày 30/09/2018

Đây là Class router theo ý tưởng của mình:

<?php
/**
 * Router class will load requested controller / closure based on url.
 */
class Router
{
    /**
     * Fallback for auto dispatching feature.
     *
     * @var boolean $fallback
     */
    public static $fallback = true;
    /**
     * If true - do not process other routes when match is found
     *
     * @var boolean $halts
     */
    public static $halts = true;
    /**
     * Array of routes
     *
     * @var array $routes
     */
    public static $routes = array();
    /**
     * Array of methods
     *
     * @var array $methods
     */
    public static $methods = array();
    /**
     * Array of callbacks
     *
     * @var array $callbacks
     */
    public static $callbacks = array();
    /**
     * Set an error callback
     *
     * @var null $errorCallback
     */
    public static $errorCallback;
    /** Set route patterns */
    public static $patterns = array(
        ':any' => '[^/]+',
        ':num' => '-?[0-9]+',
        ':all' => '.*'
    );
    /**
     * Defines a route with or without callback and method.
     *
     * @param string $method
     * @param array @params
     */
    public static function __callstatic($method, $params)
    {
        $uri = dirname($_SERVER['PHP_SELF']).'/'.$params[0];
        $callback = $params[1];
        array_push(self::$routes, $uri);
        array_push(self::$methods, strtoupper($method));
        array_push(self::$callbacks, $callback);
    }
    /**
     * Defines callback if route is not found.
     *
     * @param string $callback
     */
    public static function error($callback)
    {
        self::$errorCallback = $callback;
    }
    /**
     * Don't load any further routes on match.
     *
     * @param  boolean $flag
     */
    public static function haltOnMatch($flag = true)
    {
        self::$halts = $flag;
    }
    /**
     * Call object and instantiate.
     *
     * @param  object $callback
     * @param  array  $matched  array of matched parameters
     * @param  string $msg
     */
    public static function invokeObject($callback, $matched = null, $msg = null)
    {
        $last = explode('/', $callback);
        $last = end($last);
        $segments = explode('@', $last);
        $controller = $segments[0];
        $method = $segments[1];
        $controller = new $controller($msg);
        call_user_func_array(array($controller, $method), $matched ? $matched : array());
    }
    /**
     * autoDispatch by Volter9.
     *
     * Ability to call controllers in their controller/model/param way.
     */
    public static function autoDispatch()
    {
        $uri = parse_url($_SERVER['QUERY_STRING'], PHP_URL_PATH);
        $uri = trim($uri, ' /');
        $uri = ($amp = strpos($uri, '&')) !== false ? substr($uri, 0, $amp) : $uri;
        $parts = explode('/', $uri);
        $controller = array_shift($parts);
        $controller = $controller ? $controller : DEFAULT_CONTROLLER;
        $controller = ucwords($controller);
        $method = array_shift($parts);
        $method = $method ? $method : DEFAULT_METHOD;
        $args = !empty($parts) ? $parts : array();
        // Check for file
        if (!file_exists("app/Controllers/$controller.php")) {
            return false;
        }
        $controller = "\Controllers\\$controller";
        $c = new $controller;
        if (method_exists($c, $method)) {
            $c->$method($args);
            //found method so stop
            return true;
        }
        return false;
    }
    /**
     * Runs the callback for the given request.
     */
    public static function dispatch()
    {
        $uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
        $method = $_SERVER['REQUEST_METHOD'];
        $searches = array_keys(static::$patterns);
        $replaces = array_values(static::$patterns);
        self::$routes = str_replace('//', '/', self::$routes);
        $found_route = false;
        // parse query parameters
        $query = '';
        $q_arr = array();
        if (strpos($uri, '&') > 0) {
            $query = substr($uri, strpos($uri, '&') + 1);
            $uri = substr($uri, 0, strpos($uri, '&'));
            $q_arr = explode('&', $query);
            foreach ($q_arr as $q) {
                $qobj = explode('=', $q);
                $q_arr[] = array($qobj[0] => $qobj[1]);
                if (!isset($_GET[$qobj[0]])) {
                    $_GET[$qobj[0]] = $qobj[1];
                }
            }
        }
        // check if route is defined without regex
        if (in_array($uri, self::$routes)) {
            $route_pos = array_keys(self::$routes, $uri);
            // foreach route position
            foreach ($route_pos as $route) {
                if (self::$methods[$route] == $method || self::$methods[$route] == 'ANY') {
                    $found_route = true;
                    //if route is not an object
                    if (!is_object(self::$callbacks[$route])) {
                        //call object controller and method
                        self::invokeObject(self::$callbacks[$route]);
                        if (self::$halts) {
                            return;
                        }
                    } else {
                        //call closure
                        call_user_func(self::$callbacks[$route]);
                        if (self::$halts) {
                            return;
                        }
                    }
                }
            }
            // end foreach
        } else {
            // check if defined with regex
            $pos = 0;
            // foreach routes
            foreach (self::$routes as $route) {
                $route = str_replace('//', '/', $route);
                if (strpos($route, ':') !== false) {
                    $route = str_replace($searches, $replaces, $route);
                }
                if (preg_match('#^' . $route . '$#', $uri, $matched)) {
                    if (self::$methods[$pos] == $method || self::$methods[$pos] == 'ANY') {
                        $found_route = true;
                        //remove $matched[0] as [1] is the first parameter.
                        array_shift($matched);
                        if (!is_object(self::$callbacks[$pos])) {
                            //call object controller and method
                            self::invokeObject(self::$callbacks[$pos], $matched);
                            if (self::$halts) {
                                return;
                            }
                        } else {
                            //call closure
                            call_user_func_array(self::$callbacks[$pos], $matched);
                            if (self::$halts) {
                                return;
                            }
                        }
                    }
                }
                $pos++;
            }
            // end foreach
        }
        if (self::$fallback) {
            //call the auto dispatch method
            $found_route = self::autoDispatch();
        }
        // run the error callback if the route was not found
        if (!$found_route) {
            if (!self::$errorCallback) {
                self::$errorCallback = function () {
                    header("{$_SERVER['SERVER_PROTOCOL']} 404 Not Found");
                    $data['title'] = '404';
                    $data['error'] = "Oops! Page not found..";
                    View::renderTemplate('header', $data);
                    View::render('Error/404', $data);
                    View::renderTemplate('footer', $data);
                };
            }
            if (!is_object(self::$errorCallback)) {
                //call object controller and method
                self::invokeObject(self::$errorCallback, null, 'No routes found.');
                if (self::$halts) {
                    return;
                }
            } else {
                call_user_func(self::$errorCallback);
                if (self::$halts) {
                    return;
                }
            }
        }
    }
}

các sử dụng:

Router::any('', 'Controllers\Welcome@index');
Router::any('subpage/{id}', 'Controllers\Welcome@subPage');
kid1412 viết 20:37 ngày 30/09/2018

cảm ơn @đinh quốc hân nhé. để mình xem thêm

Bài liên quan
0