Pux is a fast PHP Router and includes out-of-box controller tools

Last update: May 10, 2022

Pux

Pux is a faster PHP router, it also includes out-of-box controller helpers.

Latest Stable Version Total Downloads Latest Unstable Version License Monthly Downloads Daily Downloads

2.0.x Branch Build Status (This branch is under development)

Benchmark

FEATURES

  • Low memory footprint (only 6KB with simple routes and extension installed) .
  • Low overhead.
  • PCRE pattern path support. (Sinatra-style syntax)
  • Controller auto-mounting - you mount a controller automatically without specifying paths for each action.
  • Controller annotation support - you may override the default path from controller through the annotations.
  • Route with optional pattern.
  • Request constraints
    • Request method condition support.
    • Domain condition support.
    • HTTPS condition support.

REQUIREMENT

  • PHP 5.4+

INSTALLATION

composer require corneltek/pux "2.0.x-dev"

SYNOPSIS

The routing usage is dead simple:

require 'vendor/autoload.php'; // use PCRE patterns you need Pux\PatternCompiler class.
use Pux\RouteExecutor;

class ProductController {
    public function listAction() {
        return 'product list';
    }
    public function itemAction($id) { 
        return "product $id";
    }
}
$mux = new Pux\Mux;
$mux->any('/product', ['ProductController','listAction']);
$mux->get('/product/:id', ['ProductController','itemAction'] , [
    'require' => [ 'id' => '\d+', ],
    'default' => [ 'id' => '1', ]
]);
$mux->post('/product/:id', ['ProductController','updateAction'] , [
    'require' => [ 'id' => '\d+', ],
    'default' => [ 'id' => '1', ]
]);
$mux->delete('/product/:id', ['ProductController','deleteAction'] , [
    'require' => [ 'id' => '\d+', ],
    'default' => [ 'id' => '1', ]
]);

// If you use ExpandableController, it will automatically expands your controller actions into a sub-mux
$mux->mount('/page', new PageController);

$submux = new Pux\Mux;
$submux->any('/bar');
$mux->mount('/foo',$submux); // mount as /foo/bar

// RESTful Mux Builder
$builder = new RESTfulMuxBuilder($mux, [ 'prefix' => '/=' ]);
$builder->addResource('product', new ProductResourceController); // expand RESTful resource point at /=/product
$mux = $builder->build();


if ($route = $mux->dispatch('/product/1')) {
    $response = RouteExecutor::execute($route);

    $responder = new Pux\Responder\SAPIResponder();
    // $responder->respond([ 200, [ 'Content-Type: text/plain' ], 'Hello World' ]);
    $responder->respond($response);
}

Mux

Mux is where you define your routes, and you can mount multiple mux to a parent one.

$mainMux = new Mux;

$pageMux = new Mux;
$pageMux->any('/page1', [ 'PageController', 'page1' ]);
$pageMux->any('/page2', [ 'PageController', 'page2' ]);

// short-hand syntax
$pageMux->any('/page2', 'PageController:page2'  );

$mainMux->mount('/sub', $pageMux);

foreach( ['/sub/page1', '/sub/page2'] as $p ) {
    $route = $mainMux->dispatch($p);

    // The $route contains [ pcre (boolean), path (string), callback (callable), options (array) ]
    list($pcre, $path, $callback, $options) = $route;
}

Methods

  • Mux->add( {path}, {callback array or callable object}, { route options })
  • Mux->post( {path}, {callback array or callable object}, { route options })
  • Mux->get( {path}, {callback array or callable object}, { route options })
  • Mux->put( {path}, {callback array or callable object}, { route options })
  • Mux->any( {path}, {callback array or callable object}, { route options })
  • Mux->delete( {path}, {callback array or callable object}, { route options })
  • Mux->mount( {path}, {mux object}, { route options })
  • Mux->length() returns length of routes.
  • Mux->export() returns Mux constructor via __set_state static method in php code.
  • Mux->dispatch({path}) dispatch path and return matched route.
  • Mux->getRoutes() returns routes array.
  • Mux::__set_state({object member array}) constructs and returns a Mux object.

Sorting routes

You need to sort routes when not using compiled routes, it's because pux sorts longer path to front:

$pageMux = new Mux;
$pageMux->add('/', [ 'PageController', 'page1' ]);
$pageMux->add('/pa', [ 'PageController', 'page1' ]);
$pageMux->add('/page', [ 'PageController', 'page1' ]);
$pageMux->sort();

This sorts routes to:

/page
/pa
/

So pux first compares /page, /pa, than /.

Different String Comparison Strategies

When expand is enabled, the pattern comparison strategy for strings will match the full string.

When expand is disabled, the pattern comparison strategy for strings will match the prefix.

RouteRequest

RouteRequest maintains the information of the current request environment, it also provides some constraint checking methods that helps you to identify a request, e.g.:

if ($request->queryStringMatch(...)) {

}
if ($request->hostEqual('some.dev')) {

}
if ($request->pathEqual('/foo/bar')) {

}
use Pux\Environment;
$env = Environment::createFromGlobals();
$request = RouteRequest::createFromEnv($env);

if ($route = $mux->dispatchRequest($request)) {

}

APCDispatcher

Although Pux\Mux is already fast, you can still add APCDispatcher to boost the performance, which is to avoid re-lookup route.

This is pretty useful when you have a lot of PCRE routes.

use Pux\Dispatcher\APCDispatcher;
$dispatcher = new APCDispatcher($mux, array(
    'namespace' => 'app_',
    'expiry' => ...,
));
$route = $dispatcher->dispatch('/request/uri');
var_dump($route);

Controller

Pux provides the ability to map your controller methods to paths automatically, done either through a simple, fast controller in the C extension or its pure PHP counterpart:

class ProductController extends \Pux\Controller
{
    // translate to path ""
    public function indexAction() { }

    // translate to path "/add"
    public function addAction() { }

    // translate to path "/del"
    public function delAction() { }
}

$mux = new Pux\Mux;
$submux = $controller->expand();
$mux->mount( '/product' , $submux );

// or even simpler
$mux->mount( '/product' , $controller);

$mux->dispatch('/product');       // ProductController->indexAction
$mux->dispatch('/product/add');   // ProductController->addAction
$mux->dispatch('/product/del');   // ProductController->delAction

You can also use @Route and @Method annotations to override the default \Pux\Controller::expand() functionality:

class ProductController extends \Pux\Controller
{
    /**
     * @Route("/all")
     * @Method("GET")
     */
    public function indexAction() {
        // now available via GET /all only
    }
    
    /**
     * @Route("/create")
     * @Method("POST")
     */
    public function addAction() {
        // now available via POST /create only
    }
    
    /**
     * @Route("/destroy")
     * @Method("DELETE")
     */
    public function delAction() {
        // now available via DELETE /destroy only
    }
}

This is especially helpful when you want to provide more specific or semantic (e.g., HTTP method-specific) actions. Note that by default, expanded controller routes will be available via any HTTP method - specifying @Method will restrict it to the provided method.

  • Pux\Controller::expand() returns an instance of \Pux\Mux that contains the controller's methods mapped to URIs, intended to be mounted as a sub mux in another instance of \Pux\Mux.

Route RouteExecutor

Pux\RouteExecutor executes your route by creating the controller object, and calling the controller action method.

Route executor take the returned route as its parameter, you simply pass the route to executor the controller and get the execution result.

Here the simplest example of the usage:

use Pux\RouteExecutor;
$mux = new Pux\Mux;
$mux->any('/product/:id', ['ProductController','itemAction']);
$route = $mux->dispatch('/product/1');
$result = RouteExecutor::execute($route);

You can also define the arguments to the controller's constructor method:

class ProductController extends Pux\Controller {
    public function __construct($param1, $param2) {
        // do something you want
    }
    public function itemAction($id) {
        return "Product $id";
    }
}

use Pux\RouteExecutor;
$mux = new Pux\Mux;
$mux->any('/product/:id', ['ProductController','itemAction'], [ 
    'constructor_args' => [ 'param1', 'param2' ],
]);
$route = $mux->dispatch('/product/1');
$result = RouteExecutor::execute($route); // returns "Product 1"

Dispatching Strategy

There are two route dispatching strategies in Pux while Symfony/Routing only provides PCRE pattern matching:

  1. Plain string comparison.
  2. PCRE pattern comparison.

You've already knew that PCRE pattern matching is slower than plain string comparison, although PHP PCRE caches the compiled patterns.

The plain string comparison is designed for static routing paths, it improves the performance while you have a lot of simple routes.

The PCRE pattern comparison is used when you have some dynamic routing paths, for example, you can put some place holders in your routing path, and pass these path arguments to your controller later.

Pux sorts and compiles your routes to single cache file, it also uses longest matching so it sorts patterns by pattern length in descending order before compiling the routes to cache.

Pux uses indexed array as the data structure for storing route information so it's faster.

Routing Path Format

Static route:

/post

PCRE route:

/post/:id                  => matches /post/33

PCRE route with optional pattern:

/post/:id(/:title)         => matches /post/33, /post/33/post%20title
/post/:id(\.:format)       => matches /post/33, /post/33.json .. /post/33.xml

Q & A

Why It's Faster

  • Pux uses simpler data structure (indexed array) to store the patterns and flags. (In PHP internals, zend_hash_index_find is faster than zend_hash_find).

  • When matching routes, symfony uses a lot of function calls for each route:

    https://github.com/symfony/Routing/blob/master/Matcher/UrlMatcher.php#L124

    Pux fetches the pattern from an indexed-array:

    https://github.com/c9s/Pux/blob/master/src/Pux/Mux.php#L189

  • Even you enabled APC or other bytecode cache extension, you are still calling methods and functions in the runtime. Pux reduces the route building to one static method call. __set_state.

  • Pux separates static routes and dynamic routes automatically, Pux uses hash table to look up static routes without looping the whole route array.

  • Pux\Mux is written in C extension, method calls are faster!

  • With C extension, there is no class loading overhead.

  • Pux compiles your routes to plain PHP array, the compiled routes can be loaded very fast. you don't need to call functions to register your routes before using it.

Why It's Here

Most of us use a lot of machines to run our applications, however, it uses too much energy and too many resources.

Some people thinks routing is not the bottleneck, the truth is this project does not claim routing is the bottleneck.

Actually the "bottleneck" is always different in different applications, if you have a lot of heavy db requests, then your bottleneck is your db; if you have a lot of complex computation, then the bottleneck should be your algorithm.

You might start wondering since the bottleneck is not routing, why do we implement route dispatcher in C extension? The answer is simple, if you put a pure PHP routing component with some empty callbacks and use apache benchmark tool to see how many requests you can handle per second, you will find out the routing component consumes a lot of computation time and the request number will decrease quite a few. (and it does nothing, all it does is ... just routing)

Pux tries to reduce the overheads of loading PHP classes and the runtime method/function calls, and you can run your application faster without the overheads.

Pros & Cons of Grouped Pattern Matching Strategy

An idea of matching routes is to combine all patterns into one pattern and compare the given path with pcre_match in one time.

However this approach does not work if you have optional group or named capturing group, the pcre_match can not return detailed information about what pattern is matched if you use one of them.

And since you compile all patterns into one, you can't compare with other same patterns with different conditions, for example:

/users  # GET
/users  # POST
/users  # with HTTP_HOST=somedomain

The trade off in Pux is to compare routes in sequence because the same pattern might be in different HTTP method or different host name.

The best approach is to merge & compile the regexp patterns into a FSM (Finite state machine), complex conditions can also be merged into this FSM, and let this FSM to dispatch routes. And this is the long-term target of Pux.

Contributing

Testing XHProf Middleware

Define your XHPROF_ROOT in your phpunit.xml, you can copy phpunit.xml.dist to phpunit.xml, for example:

  <php>
    <env name="XHPROF_ROOT" value="/Users/c9s/src/php/xhprof"/>
  </php>

Hacking Pux C extension

  1. Discuss your main idea on GitHub issue page.

  2. Fork this project and open a branch for your hack.

  3. Development Cycle:

     cd ext
     ./compile
     ... hack hack hack ...
    
     # compile and run phpunit test
     ./compile && ./test -- --debug tests/Pux/MuxTest.php
    
     # use lldb to debug extension code
     ./compile && ./test -l -- tests/Pux/MuxTest.php
    
     # use gdb to debug extension code
     ./compile && ./test -g -- tests/Pux/MuxTest.php
    
  4. Commit!

  5. Send pull request and describe what you've done and what is changed.

GitHub

https://github.com/c9s/Pux
Comments
  • 1. Persistent Mux in the extension

    To improve even more the performance, you can make create an alias for the Mux class and it be stored in the extension persistent memory.

    For web requests, the first request will load from the compiled router file. For subsequent request it can use the persisted object in memory. It will avoid file access to read the compiled file and re-load all the objects for every request.

    You can make something like:

    $mux = \Pux\MuxCache::load('compiled_router.php', 'app_routes');
    // If not stored, include compiled_router and persist it, otherwise just use the persisted object from app_routes alias
    
    \Pux\MuxCache::clear(); // Remove all persisted objects
    

    Something like that. Thoughts?

    Reviewed by jrbasso at 2014-01-15 03:40
  • 2. Feature/annotation

    As discussed in #36, this now provides the ability to use docblocks, specifically @method and @uri variables. For example:

        <?php
        class MyController {
            /**
             * @uri /foo
             * @method OPTIONS
             */
            public function indexAction() {
                echo 'This is only available via: OPTIONS /foo';
            }
        }
    

    Note that @uri is only relative to a mount point if specified, e.g.:

    $mux->mount('/mountpoint', $controller->expand());
    

    but will override the default uri generated from the action names.

    Reviewed by mway at 2014-02-18 14:02
  • 3. Add Pux pure PHP to the benchmark information

    I hate to say it, but comparing a C extension to a pure PHP implementation is like comparing a racehorse against a donkey. Especially for something like this. So saying the extension is faster than the Symphony router isn't saying much.

    Personally, I'd like to know where the pure PHP implementation of Pux stands in relation to the extension, as well as other libraries.

    Reviewed by rk at 2014-01-14 14:54
  • 4. Expanded controller HTTP methods

    Hello! I started using Pux a while back but ran into some issues with URI collisions and using $controller->expand() with HTTP methods, so thought I'd make some tweaks. I haven't written/contributed to a PHP extension before, so I apologize in advance if any of the Zend API idioms or general extension best practices aren't observed - please let me know if there's anything you'd like rewritten.

    Purpose

    The purpose of this change is to allow registering HTTP method-specific controller actions via \Pux\Controller::expand(), and also allow those actions to share the same URIs (previously they would overwrite each other). This is especially useful for using Pux as a router for a micro REST framework, e.g., not needing to use separate URIs (e.g., /users + /users/create) where there is generally only one (/users). With these changes, it is possible to do something like

    <?php
    
    class MyController extends \Pux\Controller {
        # GET /
        public function indexAction() {
            echo 'Index!';
        }
    
        # POST /
        public function indexPostAction() {
            echo 'Index post!';
        }
    }
    
    $c      = new MyController():
    $mux    = new Pux\Mux();
    $mux->mount(null, $c->expand());
    

    and then:

    curl localhost/
    #=> Index!
    
    curl -X localhost/
    #=> Index post!
    

    rather than either explicitly registering each route with \Pux\Mux, or detecting $_SERVER['REQUEST_METHOD'] in the action and potentially needing to either a) mix code with significantly different intentions or b) make additional method calls to separate it out.

    PHP + extension changes

    1. Controller::getActionPaths() members now include a normalized HTTP method as a string (GET|PUT|POST|DELETE)
      • Note this HTTP method is not included in the URI, so endpoints can be shared (e.g., GET /comments for listing vs. POST /comments for creating)
    2. Changed Mux::mount() to:
      • Enforce at least a root URI (/) if null or an empty string is passed, instead of warning
      • Merge both the passed $options and route options arrays when adding each route
    3. Changed Controller::expand() to:
      • Now read $options array from Controller::getActionPaths() result
      • Will translate the HTTP method string (if provided) to the int constant expected by Mux::add()
      • Now passes $options to Mux::add()

    Extension-only changes

    1. Added Mux::getRequestMethodConstant() (previously only existed in PHP)
    Reviewed by mway at 2014-02-14 21:50
  • 5. Symfony 2 Routing test

    Just to fully understand and replicate your benchmark, don't you think it would be fair to include the code you've used to test the Symfony Routing component? For example, did you enable the cache_dir for the Symfony Routing component before running the tests? https://symfony2-document.readthedocs.org/en/latest/components/routing.html#the-all-in-one-router

    Thanks!

    Reviewed by giorrrgio at 2014-01-12 22:44
  • 6. Optimizations

    Optimized php_controller.c

    • getActionMethods(): operate directly on return_value, do not create an intermediate zval
    • getActionPaths(): use zend_hash_quick_find() instead of zend_hash_quick_find(): gcc will compute the value of zend_inline_hash_func() during compile time
    • use array_init_size() instead of array_init() when the size of the array is known in advance
    • use MAKE_STD_ZVAL instead of ALLOC_INIT_ZVAL where the type of zval is set explicitly

    Optimized php_functions.c:

    • Use zend_hash_quick_find() instead of zend_hash_find()

    Optimized php_mux.c:

    • Use zend_hash_quick_find() instead of zend_hash_find()
    • Use zend_hash_quick_update() instead of zend_hash_update()
    • Use MAKE_STD_ZVAL instead of ALLOC_INIT_ZVAL
    • Use array_init_size() where the size of the array is known
    • Use native var_export (php_var_export_ex from ext/standard/php_var.h) instead of a slow call to the userspace
    • Use pointer arithmetics instead of a slow call to the userspace substr()
    Reviewed by ghost at 2014-01-19 06:10
  • 7. Best way to benchmark my controller methods

    Hi everybody,

    Thanks a lot for putting this amazing router together! We are starting to use this on production, hopefully everything is going to be smooth.

    I have a question. In development mode, we try to benchmark our controllers' methods. We are using https://github.com/nshahzad/codon-profiler for this purpose. My question is:

    Is there a way for us to hook into dispatcher and possible run a closure before and after the route execution? So that we can gather memory and time data before and after the controller and provide a performance result.

    Otherwise we will be putting these measures before and after Pux\Executor::execute() method. Do you think this is fine and does not add a lot between our execute() call and the actual method call inside the controller?

    Thanks again for this package.

    Reviewed by oytuntez at 2015-03-02 18:32
  • 8. route '/' handling differs

    Sample code:

    <?php
    require __DIR__ . '/../vendor/autoload.php';
    $mux = new Pux\Mux;
    $mux->add('/', [ 'PageController', 'page1' ]);
    $route = $mux->dispatch('/abc');
    var_dump($route);
    

    Result of 1.4.0:

    NULL
    

    Result of 1.5.0:

    array(4) {
      [0] =>
      bool(false)
      [1] =>
      string(1) "/"
      [2] =>
      array(2) {
        [0] =>
        string(14) "PageController"
        [1] =>
        string(5) "page1"
      }
      [3] =>
      array(0) {
      }
    }
    

    Is this a bug or not?

    Reviewed by kenjis at 2014-02-27 02:32
  • 9. Annotation value case exception?

    Hi @mway,

    The doc_var_len is decided by a space char. but what if an user ends the line with \n not a space? that might return a path like /path\n?

    https://github.com/c9s/Pux/blob/40b1c1bf44a62f8c568d9b3c5b8aa7ed334f9ed6/ext/pux_controller.c#L130

    Is it possible to read the Route like Symfony do? because our annotation actually reads this syntax:

    class PostController extends Controller
    {
        /**
         * @Route("/")
         * @Method("GET")
         */
        public function indexAction()
        {
            // ...
        }
    }
    
    Reviewed by c9s at 2014-02-19 03:37
  • 10. default action path for indexAction from controller

    Hi @mway

    it seems the path for indexAction is defined to / by default, however if we mount a controller to something like "/product" we got "/product/", the correct path should be /product.

    I think the default path of indexAction should be an empty string. :-)

    you may run the unit test to see the result:

     cd ext/
     ./compile && ./run-test -- test/Pux/ControllerTest.php
    
    Reviewed by c9s at 2014-02-19 00:35
  • 11. undefined symbol: _pux_store_mux

    I'm getting the following error when trying to use the extension:

    PHP Startup: Unable to load dynamic library '/usr/lib/php5/20131226/pux.so' - /usr/lib/php5/20131226/pux.so: undefined symbol: _pux_store_mux in Unknown on line 0

    Here is what I did:

    git clone https://github.com/c9s/Pux.git
    cd Pux/ext
    ./compile -i
    
    + do_clean=0
    + do_install=0
    + do_phpize=0
    + getopts cip o
    + case "${o}" in
    + do_install=1
    + getopts cip o
    + [[ 0 == 1 ]]
    + [[ ! -e configure ]]
    + echo '===> Found change, scaffolding...'
    ===> Found change, scaffolding...
    + phpize --clean
    + phpize
    Configuring for:
    PHP Api Version:         20131106
    Zend Module Api No:      20131226
    Zend Extension Api No:   220131226
    + [[ ! -e Makefile ]]
    + echo '===> Configuring...'
    ===> Configuring...
    + ./configure
    configure: WARNING: You will need re2c 0.13.4 or later if you want to regenerate PHP parsers.
    + [[ 0 == 1 ]]
    + echo '===> Building...'
    ===> Building...
    + make
    /home/rudi/Desktop/Pux/ext/pux_controller.c: In function 'zend_parse_action_annotations':
    /home/rudi/Desktop/Pux/ext/pux_controller.c:290:9: warning: passing argument 4 of 'add_assoc_stringl_ex' discards 'const' qualifier from pointer target type [enabled by default]
             add_assoc_stringl(z_route_meta, "class", ce->name, ce->name_length, 1);
             ^
    In file included from /usr/include/php5/main/php.h:40:0,
                     from /home/rudi/Desktop/Pux/ext/pux_controller.c:3:
    /usr/include/php5/Zend/zend_API.h:385:14: note: expected 'char *' but argument is of type 'const char *'
     ZEND_API int add_assoc_stringl_ex(zval *arg, const char *key, uint key_len, char *str, uint length, int duplicate);
                  ^
    /home/rudi/Desktop/Pux/ext/ct_helper.c: In function 'find_place_holder':
    /home/rudi/Desktop/Pux/ext/ct_helper.c:110:5: warning: return discards 'const' qualifier from pointer target type [enabled by default]
         return php_memnstr(pattern, needle_char, 1, (char*) pattern + pattern_len);
         ^
    + [[ 1 == 1 ]]
    + echo '===> Installing...'
    ===> Installing...
    + make install
    Installing shared extensions:     /usr/lib/php5/20131226/
    

    I also added extension=pux.so to my CLI php.ini

    PHP 5.6.13-1+deb.sury.org~trusty+3 (cli)

    Reviewed by rtheunissen at 2015-09-18 07:40
  • 12. Raw url with slashes.

    Why there is no pattern to match dynamic paths? Something like this: https://website.com/search/:a-lot-of-filters to match all variants of url https://website.com/search/filter-1/filter-2/filter-8/filter-n. I want to parse this string by myself with parse_url, without using patterns after search. In symfony i can do the following: (new RouteCollection)->add("search", new Route("/search/{any}", ["controller" => AppBundle:Default:search"], ["any" => ".+"]));

    Reviewed by ddv88 at 2017-09-26 15:04
  • 13. Compilation errors on PHP7 while installing extension

    Facing this issue:

    PHP is compiled and installed at a custom path.

    [[email protected] ext]#
    [[email protected] ext]# php -v
    PHP 7.0.13 (cli) (built: Nov 25 2016 12:27:01) ( NTS )
    Copyright (c) 1997-2016 The PHP Group
    Zend Engine v3.0.0, Copyright (c) 1998-2016 Zend Technologies
        with Zend OPcache v7.0.13, Copyright (c) 1999-2016, by Zend Technologies
    [[email protected] ext]#
    [[email protected] ext]# ./configure
    -bash: ./configure: No such file or directory
    [[email protected] ext]#
    [[email protected] ext]#
    [[email protected] ext]#
    [[email protected] ext]# php -v
    PHP 7.0.13 (cli) (built: Nov 25 2016 12:27:01) ( NTS )
    Copyright (c) 1997-2016 The PHP Group
    Zend Engine v3.0.0, Copyright (c) 1998-2016 Zend Technologies
        with Zend OPcache v7.0.13, Copyright (c) 1999-2016, by Zend Technologies
    [[email protected] ext]#
    [[email protected] ext]#
    [[email protected] ext]# phpize
    Configuring for:
    PHP Api Version:         20151012
    Zend Module Api No:      20151012
    Zend Extension Api No:   320151012
    [[email protected] ext]# ./configure
    checking for grep that handles long lines and -e... /bin/grep
    checking for egrep... /bin/grep -E
    checking for a sed that does not truncate output... /bin/sed
    checking for cc... cc
    checking whether the C compiler works... yes
    checking for C compiler default output file name... a.out
    checking for suffix of executables...
    checking whether we are cross compiling... no
    checking for suffix of object files... o
    checking whether we are using the GNU C compiler... yes
    checking whether cc accepts -g... yes
    checking for cc option to accept ISO C89... none needed
    checking how to run the C preprocessor... cc -E
    checking for icc... no
    checking for suncc... no
    checking whether cc understands -c and -o together... yes
    checking for system library directory... lib
    checking if compiler supports -R... no
    checking if compiler supports -Wl,-rpath,... yes
    checking build system type... x86_64-unknown-linux-gnu
    checking host system type... x86_64-unknown-linux-gnu
    checking target system type... x86_64-unknown-linux-gnu
    checking for PHP prefix... /server/php7
    checking for PHP includes... -I/server/php7/include/php -I/server/php7/include/php/main -I/server/php7/include/php/TSRM -I/server/php7/include/php/Zend -I/server/php7/include/php/ext -I/server/php7/include/php/ext/date/lib
    checking for PHP extension directory... /server/php7/lib/php/extensions/no-debug-non-zts-20151012
    checking for PHP installed headers prefix... /server/php7/include/php
    checking if debug is enabled... no
    checking if zts is enabled... no
    checking for re2c... no
    configure: WARNING: You will need re2c 0.13.4 or later if you want to regenerate PHP parsers.
    checking for gawk... gawk
    checking Whether to enable the "pux" extension... yes, shared
    checking if PUX should be built in debug mode... no
    checking for ld used by cc... /bin/ld
    checking if the linker (/bin/ld) is GNU ld... yes
    checking for /bin/ld option to reload object files... -r
    checking for BSD-compatible nm... /bin/nm -B
    checking whether ln -s works... yes
    checking how to recognize dependent libraries... pass_all
    checking for ANSI C header files... yes
    checking for sys/types.h... yes
    checking for sys/stat.h... yes
    checking for stdlib.h... yes
    checking for string.h... yes
    checking for memory.h... yes
    checking for strings.h... yes
    checking for inttypes.h... yes
    checking for stdint.h... yes
    checking for unistd.h... yes
    checking dlfcn.h usability... yes
    checking dlfcn.h presence... yes
    checking for dlfcn.h... yes
    checking the maximum length of command line arguments... 1572864
    checking command to parse /bin/nm -B output from cc object... ok
    checking for objdir... .libs
    checking for ar... ar
    checking for ranlib... ranlib
    checking for strip... strip
    checking if cc supports -fno-rtti -fno-exceptions... no
    checking for cc option to produce PIC... -fPIC
    checking if cc PIC flag -fPIC works... yes
    checking if cc static flag -static works... no
    checking if cc supports -c -o file.o... yes
    checking whether the cc linker (/bin/ld -m elf_x86_64) supports shared libraries... yes
    checking whether -lc should be explicitly linked in... no
    checking dynamic linker characteristics... GNU/Linux ld.so
    checking how to hardcode library paths into programs... immediate
    checking whether stripping libraries is possible... yes
    checking if libtool supports shared libraries... yes
    checking whether to build shared libraries... yes
    checking whether to build static libraries... no
    
    creating libtool
    appending configuration tag "CXX" to libtool
    configure: creating ./config.status
    config.status: creating config.h
    [[email protected] ext]# make
    /bin/sh /tmp/Pux-1.6/ext/libtool --mode=compile cc  -I. -I/tmp/Pux-1.6/ext -DPHP_ATOM_INC -I/tmp/Pux-1.6/ext/include -I/tmp/Pux-1.6/ext/main -I/tmp/Pux-1.6/ext -I/server/php7/include/php -I/server/php7/include/php/main -I/server/php7/include/php/TSRM -I/server/php7/include/php/Zend -I/server/php7/include/php/ext -I/server/php7/include/php/ext/date/lib -I/opt/local/include  -DHAVE_CONFIG_H  -g -O2   -c /tmp/Pux-1.6/ext/php_pux.c -o php_pux.lo
    mkdir .libs
     cc -I. -I/tmp/Pux-1.6/ext -DPHP_ATOM_INC -I/tmp/Pux-1.6/ext/include -I/tmp/Pux-1.6/ext/main -I/tmp/Pux-1.6/ext -I/server/php7/include/php -I/server/php7/include/php/main -I/server/php7/include/php/TSRM -I/server/php7/include/php/Zend -I/server/php7/include/php/ext -I/server/php7/include/php/ext/date/lib -I/opt/local/include -DHAVE_CONFIG_H -g -O2 -c /tmp/Pux-1.6/ext/php_pux.c  -fPIC -DPIC -o .libs/php_pux.o
    In file included from /tmp/Pux-1.6/ext/php_pux.c:15:0:
    /tmp/Pux-1.6/ext/php_pux.h:90:27: error: unknown type name ‘zend_rsrc_list_entry’
     void pux_mux_le_hash_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC);
                               ^
    /tmp/Pux-1.6/ext/php_pux.c: In function ‘pux_init_exception’:
    /tmp/Pux-1.6/ext/php_pux.c:51:3: error: too many arguments to function ‘zend_register_internal_class_ex’
       ce_pux_exception = zend_register_internal_class_ex(&e, (zend_class_entry*)zend_exception_get_default(TSRMLS_C), NULL TSRMLS_CC);
       ^
    In file included from /server/php7/include/php/main/php.h:39:0,
                     from /tmp/Pux-1.6/ext/php_pux.c:5:
    /server/php7/include/php/Zend/zend_API.h:290:28: note: declared here
     ZEND_API zend_class_entry *zend_register_internal_class_ex(zend_class_entry *class_entry, zend_class_entry *parent_ce);
                                ^
    /tmp/Pux-1.6/ext/php_pux.c: At top level:
    /tmp/Pux-1.6/ext/php_pux.c:54:27: error: unknown type name ‘zend_rsrc_list_entry’
     void pux_mux_le_hash_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
                               ^
    /tmp/Pux-1.6/ext/php_pux.c: In function ‘zm_startup_pux’:
    /tmp/Pux-1.6/ext/php_pux.c:97:63: error: ‘pux_mux_le_hash_dtor’ undeclared (first use in this function)
       le_mux_hash_table = zend_register_list_destructors_ex(NULL, pux_mux_le_hash_dtor, "hash table", module_number);
                                                                   ^
    /tmp/Pux-1.6/ext/php_pux.c:97:63: note: each undeclared identifier is reported only once for each function it appears in
    make: *** [php_pux.lo] Error 1
    

    Please suggest.

    Reviewed by iKevinShah at 2017-02-17 06:22
  • 14. recipe for target 'pux_functions.lo' failed

    /bin/bash /home/Pux/ext/libtool --mode=compile cc -I. -I/home/Pux/ext -DPHP_ATOM_INC -I/home/Pux/ext/include -I/home/Pux/ext/main -I/home/Pux/ext -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -I/opt/local/include -DHAVE_CONFIG_H -g -O2 -c /home/Pux/ext/pux_functions.c -o pux_functions.lo cc -I. -I/home/Pux/ext -DPHP_ATOM_INC -I/home/Pux/ext/include -I/home/Pux/ext/main -I/home/Pux/ext -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -I/opt/local/include -DHAVE_CONFIG_H -g -O2 -c /home/Pux/ext/pux_functions.c -fPIC -DPIC -o .libs/pux_functions.o /home/Pux/ext/pux_functions.c: In function ‘my_copy_zval’: /home/Pux/ext/pux_functions.c:80:10: error: ‘IS_CONSTANT_ARRAY’ undeclared (first use in this function) case IS_CONSTANT_ARRAY: ^ /home/Pux/ext/pux_functions.c:80:10: note: each undeclared identifier is reported only once for each function it appears in /home/Pux/ext/pux_functions.c: In function ‘my_zval_copy_ctor_func’: /home/Pux/ext/pux_functions.c:123:14: error: ‘IS_CONSTANT_ARRAY’ undeclared (first use in this function) case IS_CONSTANT_ARRAY: { ^ /home/Pux/ext/pux_functions.c: In function ‘my_zval_copy_ctor_persistent_func’: /home/Pux/ext/pux_functions.c:179:14: error: ‘IS_CONSTANT_ARRAY’ undeclared (first use in this function) case IS_CONSTANT_ARRAY: { ^ Makefile:193: recipe for target 'pux_functions.lo' failed make: *** [pux_functions.lo] Error 1

    Reviewed by surjit at 2017-01-15 08:59
  • 15. Using ? instead of /

    Hey, I'm trying to add a route to my website with tools?p=K94rF pattern and not /tools/K94rF. So i've written: $router->get('/tools?p=:p_id', [ToolsController::class, 'actionGetTools'], [ 'require' => [ 'p_id' => '[a-zA-Z0-9_-]{5}', ], 'default' => [ 'p_id' => '', ] ]);

    And it is not working, so i tried to change it from ? to /, like this: $router->get('/tools/:p_id', [ToolsController::class, 'actionGetTools'], [ 'require' => [ 'p_id' => '[a-zA-Z0-9_-]{5}', ], 'default' => [ 'p_id' => '', ] ]);

    And it works perfect. I need the routing with ? (the first one), there is any other way to implement it ?

    Thank you 😄

    Reviewed by bnsd55 at 2016-10-17 14:20
Related tags
Simple, fast and yet powerful PHP router that is easy to get integrated and in any project.

Simple, fast and yet powerful PHP router that is easy to get integrated and in any project. Heavily inspired by the way Laravel handles routing, with both simplicity and expand-ability in mind.

May 17, 2022
PhpRouter is a powerful, lightweight, and very fast HTTP URL router for PHP projects.

PhpRouter PhpRouter is a powerful, lightweight, and very fast HTTP URL router for PHP projects. Some of the provided features: Route parameters Predef

May 18, 2022
A lightweight and fast router for PHP
A lightweight and fast router for PHP

Piko Router A lightweight and blazing fast router (see benchmarks) using a radix trie to store dynamic routes. This router maps routes to user defined

Mar 28, 2022
klein.php is a fast & flexible router for PHP 5.3+

Klein.php klein.php is a fast & flexible router for PHP 5.3+ Flexible regular expression routing (inspired by Sinatra) A set of boilerplate methods fo

May 19, 2022
Fast request router for PHP

FastRoute - Fast request router for PHP This library provides a fast implementation of a regular expression based router. Blog post explaining how the

May 20, 2022
Flight routing is a simple, fast PHP router that is easy to get integrated with other routers.

The PHP HTTP Flight Router divineniiquaye/flight-routing is a HTTP router for PHP 7.1+ based on PSR-7 and PSR-15 with support for annotations, created

Nov 12, 2021
A fast & flexible router

Klein.php klein.php is a fast & flexible router for PHP 5.3+ Flexible regular expression routing (inspired by Sinatra) A set of boilerplate methods fo

May 19, 2022
Toro is a PHP router for developing RESTful web applications and APIs.

Toro Toro is a PHP router for developing RESTful web applications and APIs. It is designed for minimalists who want to get work done. Quick Links Offi

May 3, 2022
A lightweight and simple object oriented PHP Router

bramus/router A lightweight and simple object oriented PHP Router. Built by Bram(us) Van Damme (https://www.bram.us) and Contributors Features Support

May 20, 2022
A web router implementation for PHP.
A web router implementation for PHP.

Aura.Router Powerful, flexible web routing for PSR-7 requests. Installation and Autoloading This package is installable and PSR-4 autoloadable via Com

Apr 16, 2022
:bird: Simple PHP router

Macaw Macaw is a simple, open source PHP router. It's super small (~150 LOC), fast, and has some great annotated source code. This class allows you to

May 22, 2022
A simple PHP Router

Panda Router Description the panda-router is a small alternative PHP router that can be used for small projects. With this router you can use differen

Dec 27, 2021
Fast PSR-7 based routing and dispatch component including PSR-15 middleware, built on top of FastRoute.

Route This package is compliant with PSR-1, PSR-2, PSR-4, PSR-7, PSR-11 and PSR-15. If you notice compliance oversights, please send a patch via pull

May 1, 2022
PHP routing class. Lightweight yet flexible. Supports REST, dynamic and reversed routing.

AltoRouter AltoRouter is a small but powerful routing class, heavily inspired by klein.php. $router = new AltoRouter(); // map homepage $router->map(

May 6, 2022
Simple and minimal yet another PHP 7 Framework

DemirApp Minimal PHP Framework Introduction Simple and minimal yet another PHP 7 Framework Features Simple routing Simple container (Dependency Inject

Feb 12, 2022
route:menu gives you a beautiful route list which is friendly on smaller terminals and brings a few new features in.
route:menu gives you a beautiful route list which is friendly on smaller terminals and brings a few new features in.

Laravel Route Menu Your route:list, sir. route:menu gives you a beautiful route list which is friendly on smaller terminals and brings a few new featu

Apr 29, 2022
Generate a PHP script for faster routing :rocket:
Generate a PHP script for faster routing :rocket:

SwitchRoute Generating a PHP script for faster routing. The traditional way of routing uses regular expressions. This method was improved by FastRoute

Apr 14, 2022
Convention based routing for PHP

Croute Convention based routing for PHP based on Symfony components. Croute is great because: You don't need to maintain a routing table Promotes cons

Nov 9, 2021
PHP routing (like laravel) (not complete yet)

PHP Router (under construction) This repository contains routing classes that enables you to define your routes similar to laravel 8 routes. Features

Jan 16, 2022