Slim: getInstance gone

Created on 7 Jan 2016  Â·  14Comments  Â·  Source: slimphp/Slim

hey Guys,

I need the getInstance static method because the application i am writing relies on a way to get the App object from any given class. I can probably make a PR to add this feature but i was wondering why it was removed in 3.x ?

Slim 3 question

Most helpful comment

global $app will also work…

All 14 comments

Why not just add the app object to the container?

@AndrewCarterUK i honestly cannot find a way to statically retrieve DI values

btw i know how to fix the problem for myself, but i would really like to hear why this method has been removed.

Posted on IRC, but reposting here in-case anyone else is interested:

<?php

use Slim\App;

class AppContainer
{
    private static $app = null;

    public static function getInstance()
    {
        if (null === self::$app) {
            self::$app = self::makeInstance();
        }

        return self::$app;
    }

    private static function makeInstance()
    {
        $app = new App();
        // do all logic for adding routes etc

        return $app;
    }
}

// Whenever you need it
$app1 = AppContainer::getInstance();
$app2 = AppContainer::getInstance();

if ($app1 === $app2) {
    echo 'yay, same object' . PHP_EOL;
}

$app1->run();
$app2->run();

An alternative approach:

namespace App;
class App
{
    private $slim            = null;
    private static $instance = null;

    protected function __construct()
    {
        $cfg = \App\Config::getInstance();//however you handle getting config. we use an ArrayAccess/Singleton class
        $this->slim = new \Slim\Slim($cfg);
    }


    //proxy calls to slim
    public function __call($fn,$args=[])
    {
        if(method_exists($this->slim,$fn)){
            return call_user_func_array( [$this->slim,$fn] , $args);
        }
        throw new \exception('method doesnt exist::'.$name);
    }

    //proxy all sets to slim
    public function __set($k,$v)
    {
        $this->slim->{$k} = $v;
    }

    //proxy all gets to slim __get($k)
    public function __get($k)
    {
        return $this->slim->{$k};
    }

    public static function getInstance()
    {
        return (is_null(self::$instance) ? self::$instance = new self() : self::$instance);
    }

    public static function autoload($class)
    {
        $file =  realpath( __DIR__ . str_replace('\\','/', preg_replace('/'. __NAMESPACE__ .'/','',$class,1)) . '.php');
        if(file_exists($file)){
            require $file;
        }
    }

    public static function registerAutoloader()
    {
        spl_autoload_register(__NAMESPACE__ . "\\App::autoload");
    }
}

This will still allow you to to write code in the "global" space instead of needing to place it in an app method. the con is that __call() adds additional overhead to the scope chain atleast, though we are using this setup in many large scale deployments with no problems. as a bonus, you have a built in autoloader for your namespace.

global $app will also work…

I did suggest that in IRC.

And before anyone mentions bad design, it's bad design for exactly the same reason that the static access in the above examples is.

but i would really like to hear why this method has been removed.

Just to directly answer the question...

Slim has moved towards a different approach as happens with software from time to time. Static access is considered a bad design pattern in a testable application, so the method was removed.

I think the solutions provided show a good group of ways to replicate the functionality.

Closing this as the question is answered. If anyone thinks it isn't, please re-open with comments.

@designermonkey @akrabat

I made a library (https://github.com/thecodeassassin/slim-routing-manager) and i cannot port it to Slim 3 because of this missing method. What is an alternative to App::getInstance() to get an instance of app in the following generated file that works out-of-the box without adding your own static method?

<?php


/**
 * Generated with \Slim\Routing\Manager
 *
 * on 2016-01-12 09:19:53
 */
$modTimes = array (
  '/var/www/src/project/Controller/IndexController.php' => 1452590345,
);
$app = Slim\App::getInstance();

$app->map(['GET'], "/", "\\Slim\\Controller\\IndexController:indexAction");


I can of course fix this for my own app or ship the library with a custom app but that will drastically reduce the portability of this library. What i am trying to achieve here is make annotation based routing available for Slim 3.

Thanks.

There isn't one. It's one of the BC breaks between 2 and 3.

@akrabat so what is the point of having the ability to specify a class method a the callback for a route when you cannot access the App instance in that class?

@thecodeassassin - controllers are passed the container as an argument to the constructor. Is the service you need in the container?

The app is basically a http runner in version 3. All the meat of your app should be classes stored in the container for access. All route callbacks are provided the container to their constructors. All aspects of Slim's operation other than the physical process of running the http from request to response are stored in the container, so an application needs designing to realise that structure.

I have recently built an app that reads routes from files and uses the container itself. There is only one additional RouteMapper class that requires the app, so in my bootstrap, I instantiate the app, and pass it to the route mapper, then run the app. That's all that's needed, everything else happens internally using the container.

@AndrewCarterUK wonderful! did not realise this, probably should have looked into the map method a bit more. Having the container there actually pretty much solves all of my problems because i needed access to shared services. I will update the library later.

@designermonkey yeah i think i understand the pattern you guys went for here :)

:+1:

@akrabat is there a downside to using global $app ?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Zyles picture Zyles  Â·  4Comments

geggleto picture geggleto  Â·  4Comments

snoopy72 picture snoopy72  Â·  4Comments

codeguy picture codeguy  Â·  4Comments

RobDWaller picture RobDWaller  Â·  4Comments