Search code examples
phppdophpstormslim

How can I define PDO in SLIM Framework so that PhpStorm doesn't throw 'method not found in class' warnings?


So I stick PDO into my SLIM using this:

$container['dbh'] = function($container) {
    $config = $container->get('settings')['pdo'];
    $dsn = "{$config['engine']}:host={$config['host']};dbname={$config['database']};charset={$config['charset']}";
    $username = $config['username'];
    $password = $config['password'];

    return new PDO($dsn, $username, $password, $config['options']);
};

However, every time I use $this->dbh->execute() (or some other PDO method), PhpStorm warns me method 'execute' not found in class

Realistically it doesn't make a difference but I'd like my PhpStorm to stop warning me about things that it doesn't need to.


Solution

  • This is mostly an answer adding to @rickdenhaan's comment.

    I noticed that you're using $this, which implies you have a class somewhere.

    You can typehint dynamic/fake properties in a class like so:

    /**
     * @property PDO $dbh
     */
    class MyApp {
    }
    

    For more help, read the PHPDoc documentation, eg here.


    In some situations, you might not be able to influence the original class being instantiated. In that case, you can have a stub file; basically a class used only for type hinting:

    // Let's assume you cannot modify this class.
    class App {}
    
    // This is the stub class, we declare it as abstract to avoid instantiation by mistake.
    // We make it extend `App` to get metadata from there.
    abstract class AppStub extends App {
        /** @var PDO */
        public $dbh;
    }
    
    
    // ...later on in your code..
    /** @var AppStub $this */
    
    // tada!
    $this->dbh->execute();
    

    Controller classes approach

    Your main app + routing:

    $app = new \Slim\App();
    $app->get('/', \YourController::class . ':home');
    $app->get('/contact', \YourController::class . ':contact');
    

    And your controller:

    class YourController 
    {
       protected $container;
    
       // constructor receives container instance
       public function __construct(ContainerInterface $container) {
           $this->container = $container;
       }
    
       public function home($request, $response, $args) {
            $this->getDb()->execute();   // no IDE errors anymore!
            return $response;
       }
    
       public function contact($request, $response, $args) {
            return $response;
       }
    
       /**
        * @return PDO
        */
       protected function getDb()
       {
           return $this->container->get('dbh');
       }
    }