2
\$\begingroup\$

I've created a base structure for my project and found a way to wire classes together, I create an array of previously loaded classes and call them from the cache. I then have a static class that holds the cache and I call the static class when I need a class.

I feel that there is a much better way to do this, and maybe I'm doing something extremely wrong? How do other PHP applications do this? I'm pretty new to it, so I was wondering if anyone could advise me towards a better way to do this? It feels like it could be hugely improved.

Current directory structure:

enter image description here

The static class, I use this to get my classes (providers, I call them):

<?php declare(strict_types = 1);

namespace App;

class App {
    private static $providers = array();

    public static function getProvider($provider) {
        if (!isset(self::$providers[$provider])) {
            $providerName = 'App\Providers\\' . $provider;
            self::$providers[$provider] = new $providerName();
        }

        return self::$providers[$provider];
    }
}

Example of how I use it, I do this in all my controllers to show a view:

<?php declare(strict_types = 1);

use App\App;

namespace App\Controllers\Frontend\Guest;

class LoginController 
{
    public function getView() 
    {
        \App\App::getProvider('Template')->renderTemplate('index.html');
    }
}

Here is one of my few providers:

<?php declare(strict_types = 1);

namespace App\Providers;

class Template {
    private $twig;

    public function __construct() {
        $this->twig = new \Twig_Environment(new \Twig_Loader_Filesystem(ROOT . '/resources/templates'), array(
            'cache' => ROOT . '/storage/cache/templates',
        ));
    }

    public function renderTemplate($template) {
        echo $this->twig->render($template, array('the' => 'variables', 'go' => 'here'));
    }
}
\$\endgroup\$
1
  • 2
    \$\begingroup\$ What is the problem you're trying to solve here? Why do you need to store instances of objects to be used later on? Seems like this could create a few different issues later on. \$\endgroup\$
    – AndrewR
    Commented Feb 12, 2018 at 5:38

1 Answer 1

3
\$\begingroup\$

Looks sort of like you're trying to accomplish a singleton pattern, using the App class to control them all. Try this approach instead:

<?php
// Base / abstract class that defines a basic singleton pattern
abstract class SingletonProvider
{
  // Singleton pattern
  protected static $_instance;  
  public static function getInstance()
  {
    if(static::$_instance == null)
    {
      static::$_instance = new static();
    }
    return static::$_instance;
  }

  // Private constructor
  private function __construct() { }
}


// A specific provider class definition that inherits the singleton pattern
class MyProvider extends SingletonProvider
{
  // Class-specific instance reference
  protected static $_instance;  

  // --- CLASS INSTANCE-SPECIFIC PROPERTIES AND METHODS BELOW HERE ---

  // Class properties
  public $FieldX;

  protected function __construct()
  {
    $this->FieldX = "Hello World!";
  }
}


// Another specific provider class definition that inherits the singleton pattern
class MyOtherProvider extends SingletonProvider
{
  // Class-specific instance reference
  protected static $_instance;  

  // --- CLASS INSTANCE-SPECIFIC PROPERTIES AND METHODS BELOW HERE ---

  // Class properties
  public $FieldY;

  protected function __construct()
  {
    $this->FieldY = "Foo";
  }

  public function MakeMoreExciting($sentence)
  {
    return $sentence . "!!!!!!!!";
  }
}


// Usage examples
echo MyProvider::getInstance()->FieldX; // Hello World!
echo MyOtherProvider::getInstance()->FieldY; // Foo
echo MyOtherProvider::getInstance()->MakeMoreExciting("Hi there"); // Hi there!!!!!!!!

The "static" keyword is used for late static binding, which basically means that when you run MyOtherProvider::getInstance(), all the "static" references like "static::$_instance" resolve to the calling class, so it's like automatically determining either MyOtherProvider::$_instance or MyProvider::$_instance, depending on which class is being called.

The protected static $_instance is there to ensure that each class has its own property to hold the class instance.

In theory, you could even shorten all of this up into nothing but static methods and properties, too:

abstract class MyOtherProvider
{
  // Class properties
  public static $FieldY;

  public static function MakeMoreExciting($sentence)
  {
    return $sentence . "!!!!!!";
  }
}

echo MyOtherProvider::MakeMoreExciting("Hi there"); // Hi there!!!!!!

Although sometimes you might want an actual instance rather than just being completely static.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.