php application global settings

前端 未结 3 2014
我在风中等你
我在风中等你 2021-01-06 09:50

I have read almost all question I have found on StackOverflow on this topic, but could not find a straight answer.

Here is my code:

Application class

3条回答
  •  清酒与你
    2021-01-06 10:42

    Like Wrikken pointed out in the comment to your question, you are introducing Global State to your application. Quoting Martin Fowler on Global State (PoEAA, pg. 482f):

    Remember that any global data is always guilty until proven innocent.

    which in a nutshell means: avoid it. I leave it up to you to research on that topic though because it's out of scope for this question to discuss it in detail.

    Now, for a better alternative

    Let's assume you route all traffic to an index.php. You could then simply bootstrap/build all the components you need to fulfill the request inside that file. For instance, like this:

    spl_autoload_register(
        function($className) {
            static $classMap = array(
                'request' => '/path/from/here/to/Request.php',
                 … more mapping
            );
            require __DIR__ . $classMap[strtolower($className)];
        }
    );
    
    $config  = parse_ini_file(__DIR__ . '/path/from/here/to/config.ini');
    foreach($config['env'] as $key => $val) {
        ini_set($key, $val);
    }
    
    $router = new Router;
    $router->registerActionForRoute(
        '/product/list', 
        function($request, $response) use ($config) {
            return new ProductListAction(
                $request, $response
                new ProductMapper(
                    new ProductGateway(
                        new MySqli($config['db']['host'], …),
                        new Cache($config['cache'], …)
                    ),
                    new ProductBuilder;
                )
            );
        }
    );
    $router->registerActionForRoute(…);
    $router->execute(new Request($_GET, $_POST, $_SERVER), new Response);
    

    Granted, you rather want to include the autoloader from a separate file (because you want to autogenerate it with something like https://github.com/theseer/Autoload). And of course you could replace the closures in the Router with Builder or Factory patterns. I just used the simplest thing possible. It's (hopefully) easier to understand this way. You can check http://silex-project.org/ for a micro-framework using a more sophisticated but similar approach.

    The main benefit of this approach is that every component will get what it needs right from the start through Dependecy Injection. This will make it easier to unit-test your code because its so much easier to mock dependencies and achieve test-isolation.

    Another benefit is that you keep construction graph and collaborator graph separate, so you dont mix up those responsibility (like you would with a Singleton or otherwise putting a new keyword into classes that are supposed to be Information Experts.

提交回复
热议问题