To Static, or Not To Static

That is the question!

I’m re-doing some legacy PHP code and converting a lot of it from procedural to OOP. I’ve written a few classes that are needed by lots of other classes, like Database, Config and Prefs classes. But these classes only need to be instantiated or “initialized” once, but accessible to all classes or objects that need them. I was introduced to Singletons with a static method that instantiates itself, which works well. But I thought there could be a simpler, “cleaner” way of doing this.

After doing a bit more research, I found this interesting comment in an interesting thread on Stack Overflow about instantiated vs. static classes: http://stackoverflow.com/questions/1185605/when-to-use-static-vs-instantiated-classes/31282644#31282644

I happen to completely agree with him and like this approach. I am considering converting the 3 classes I mentioned above to have all static properties and methods, no instantiation, and instead a method called init() that basically works like the __construct() class and does any setup needed by the class, such as filling all the properties in the Prefs class with user preferences from the database that can be accessed from any other class, sort of like this:

class Prefs
{
	private static $init = false; 
	public static $timezone; 
	public static $language;
	public static $theme; 

	function __construct() {}  // not needed, will never be instantiated

	public static function init() 
	{
		if (!self::$init) {

			$prefs = DB::select("SELECT * FROM prefs WHERE id=9999"); 

			self::$timezone = $prefs['timezone'];
			self::$language = $prefs['language'];
			self::$theme = $prefs['theme'];

			// set flag to avoid re-loading if init() called again
			self::$init = true; 
		}
	}

	// Other functions related to Preferences will follow
}

This would allow me to simply call Prefs:init() in my main script once, and then all other classes can access its properties and methods using Prefs::$timezone, for example. I’d like to set up a static version of the __get() magic method so I can make all the properties protected, but I’m still working out the best way to do that.

If you read any of the other comments in that Stack Overflow thread, you’ll see lots of people saying to avoid static stuff and to pass instantiated objects to other classes that need it, blah blah blah. But I find this very cumbersome for certain classes that are needed by many other classes. I wish there were global objects, that would make things a lot easier (why aren’t there any?). But that solution I linked to above would achieve exactly what I want without self-instantiation or creating singletons.

So, what’s wrong with setting things up the way he described? Why are static properties and methods available in OOP if they should be avoided? Why is it necessary to instantiate all classes?

To be clear, I’m not developing an application that’s going to be sold or used by lots of people, so portability or unit testing is not a high priority. I know I could achieve something similar with a function library, but, I like how classes with static properties and methods keep things compartmentalized yet global without cluttering the global space.

There are. They are called (drumroll): static classes.

Until you write your first unit test …

1 Like

True! But classes aren’t exactly the same as objects.

Why are classes with static methods and properties difficult to test? I know nothing about unit testing, but, I’m able to test out my classes and objects just fine. Being the lone coder for this project probably helps.

Rather than follow the advice from that answer this is a much better read for you: https://r.je/static-methods-bad-practice.html :smiley:

Think about short-term code maintenance vs long-term. Static is short-term while dynamic is long-term. When using static classes you have to use global variables as well and the biggest problem are hidden dependencies. When you have a normal class that requires a number of other objects (in its constructor) then it’s immediately obvious what this class needs to function. With hidden dependencies it becomes hard to find out which class needs what - the larger the application the more this problem will be apparent. A large application built on static classes becomes messy.

Another big difference - static classes are not flexible. Take multiple instances as an example. When you need only a single instance then a static class might be okay but what if you need another instance one day? With a normal class you simply instantiate another object and you are good to go, while with a static class you have a big problem. It’s better to use objects from the start.

Passing needed objects around (as dependencies) is really a small price to pay for long-term ease of maintenance. This makes you code clearer, less magical, self-documenting, reusable and you will receive useful error messages early on (like missing dependency in the constructor).

2 Likes

Potentially also security is an issue. Say you have a static database class, if anyone gains access to run PHP in your application you can easily say good bye to your database, whereas if you had passed your database object as dependency injection of the objects that are going to use it solely, then the application is much more restricted and secure.

1 Like

Static classes itself are not, but any code under test that internally uses static classes (most obvious example: real database vs. test database)

I read that article twice that you linked to. I have to admit most of it goes right over my head at this point. In theory I understand and see why classes full of static properties and methods are not good in the long run, and that dependencies (in my case: Database, Config and Prefs classes, so far) should be passed into an object’s constructor. But in practice, I’m having a difficult time figuring out how to do this with my obviously limited OOP experience and knowledge.

I also found the above article on that same website, but it’s WAY over my head. While I understand the concept of Dependency Injection, I don’t know how this should be implemented in real life. The other article you linked to mentions Factories that can be used to instantiate an object with its dependencies. But that seems like a massive amount of code bloat, creating a factory class for each class to be sure it has its dependencies loaded. I don’t see how this is an improvement or more efficient way of constructing the application, to be honest. Or I’m just not understanding how these factories work.

I did come up with a very simple idea for passing dependencies to each object: putting a list of objects the class depends on in an array and passing that to each class that needs them. Here’s a simple example:

class MyClass 
{
	private $config; 
	private $db; 
	private $prefs; 

	function __construct($params)
	{
		// some code that gets dependencies from $params array
		
		$this->config = $params['config'];
		$this->db = $params['db'];
		$this->prefs = $params['prefs'];
	}
}

// Instantiate core classes

$config = new Config; 
$db = new Database; 
$prefs = new Prefs(USER_ID); // pass user id stored in constant

// add core objects to $params array and pass to class

$params = array( 'config' => $config, 
                 'db'	  => $db, 
                 'prefs'  => $prefs); 

$test = new MyClass($params); 

Simple, but, I know that this is probably not a very good solution, because if I add a dependency in the future that a bunch of classes need, I have to alter the $params array and add the appropriate property to hold the dependent object in each class that needs it. But if I had factories, I’d basically have to do the same thing, altering the factories for each class so that they recognize and inject the new dependency. So I’m guessing I don’t get how factories work in this case.

Hoo boy, not really sure I’m making much sense. :slight_smile:

It’s times like this I want to give up on OOP (again) and jump back to familiar procedural coding so I can just get the work done. I’ve been using PHP for over 15 years, and have always had a hard time wrapping my head around OOP, and just when I think I’m starting to figure it out, I learn that I know even less than I thought.

Thanks very much for your input. Where do you think i should go from here, learn more about factories? Read more about dependency injection? Find a different job?

Yes, I completely get your point about security. I’m just not really sure how to implement dependency injection in a way that’s not cumbersome or difficult to manage, such as this:

class MyClass 
{
	private $config; 
	private $db; 
	private $prefs; 

	function __construct($config, $db, $prefs)
	{		
		$this->config = $config;
		$this->db = $db;
		$this->prefs = $prefs;
	}
}

See my reply to @Lemon_Juice above for a really simple solution I came up with, but, even that is not much better than the above. Adding a new dependency would still require editing a lot of code. The only thing that solution makes easier is that I don’t have to pass the dependencies is a specific parameter order.

How do you do this in your projects?

I don’t really like passing a parameter array, just as I don’t like to have a long number of parameters in the construct. If my class is going to have a lot of configuration options then I’ll just do that through public setter methods, and leave the construct parameters for dependency injection of other objects and maybe a couple of other really important configuration options. Then once you have publicly configured my class object call your own public initialize method in my class.

1 Like

Your first “simple” idea to pass dependencies in an array is not a good one because PHP doesn’t check if you make any errors and pass wrong stuff - that code will work but there is a better way. Your second example is almost there, just add type hints to the parameters:

class MyClass 
{
	private $config; 
	private $db; 
	private $prefs; 

	function __construct(Config $config, Db $db, Prefs $prefs)
	{		
		$this->config = $config;
		$this->db = $db;
		$this->prefs = $prefs;
	}
}

Having required class names in parameters allows PHP to check if you passed the correct objects. This is good because if you make a mistake and pass a wrong object you will get a helpful error message immediately. Moreover, if you use an IDE then it will know what kind of objects are in each of your $this->... properties and give you suggestions for available methods and properties in those objects - this speeds up your development and makes it less error prone.

Going further, the object type hints in the parameters don’t have to be specific classes - they can be interfaces, which means PHP will accept any class that implements that interface. But that might be too much for you for now - I just mention so that you can come back to it once you master all the basic stuff :slight_smile:

Now, the above code is a classic example of Dependency Injection. It is a very simple concept and keep it that way for now. You mentioned Dice - it is a Dependency Injection Container - at this moment I would suggest not to go into it because it can be too much in one go, just start using Dependency Injection in this simple form. DIC is not necessary - it can help when you have a large number of objects and it will instantiate them for you (almost) automatically.

Yes, DI and then factories and just start using them. The idea is to avoid using the new keyword for object instantiation within your classes because new is like a global variable, so instead you pass constructed objects to your classes via DI. It’s pretty simple but you have to instantiate you object somewhere - you can use a factory for that and you use new in your factories only. You try to construct you application so that at the topmost layer you instantiate your necessary objects (for example via factories) and then simply execute the methods deeper in the structure that do the desired stuff. And those deeper layers (classes) of your application do not instantiate required objects but require them via DI.

If you use a framework then the topmost layer of an application is usually handled by the framework - that’s what it helps you with. The deeper layer is what the application really does. Theoretically, if you do it right then you can move the deeper layer from one framework to another and it will work because it requires all dependencies via DI and does not communicate in any other way with the outside world, the only requirement is that whatever code calls your classes provides the required dependencies. Of course, in real world it’s hard to achieve this kind of perfection but you can get close.

In a large application object instantiation can get complicated because of many dependencies. Also, you want some objects to be separate instances (most of them) but some of them only one (like a db connection), that’s why DIC’s were created. But you don’t have to go that far now, you can use a simple factory like this:

class Factory {
    public function getConfig() {
        return new Config;
    }
    
    // in some cases you want to always have the same and single
    // instance of a class:
    public function getDb() {
        static $db = null;
        
        if (isset($db)) {
            return $db;
        }
        
        $db = new Db($this->getConfig());
        return $db;
    }
    
    public function getMessageSender() {
        return new MessageSender(
            $this->getSwiftMailer(),
            $this->getLogger()
        );
    }
    
    public function getLogger() {
        return new Logger;
    }
    
    public function getSwiftMailer() {
        $conf = $this->getConfig()->smtp();
        
        // instance from external library:
        $transport = \Swift_SmtpTransport::newInstance($conf['host'], $conf['port'])
            ->setUsername($conf['username'])
            ->setPassword($conf['password']);
        
        return Swift_Mailer::newInstance($transport);
    }
    
    public function getBlogController() {
        return new BlogController(
            $this->getBlogModel(),
            $this->getTemplateEngine()
        );
    }
    
    // etc., etc., ...
}

And you instantiate one Factory object at the top of your application and then use that one instance to create your objects and execute whatever is needed for your application:

$factory = new Factory;

// a most simple router:
if ($_SERVER['REQUEST_URI'] == '/blog') {
    $controller = $factory->getBlogController();
    $controller->displayBlog(1);  // display 1st page of blog
}

and you have a very simple application based on dependency injection with no static methods! Just play with that idea and then you can go to more advanced stuff. Of course, when the app gets large you can organize your factories into several ones, for example have a separate factory for controllers, etc.

Yeah, if you can find a nice job without having to sit in front of the computer all day that would certainly be more healthy for you overall :smiley:

1 Like

Thanks so much for the detailed reply. I don’t fully understand all of it! So please excuse any dumb, newbie questions.

If found this video on YouTube that explains dependency injection fairly well with pictures, perfect for a graphic designer like me.

That video also mentions interfaces, and I’ve read about them but didn’t really understand what they are for so haven’t used them yet. I’m now intrigued and will try to figure out how they work and what they’re for in this context.

In the Factory code you posted, I have a question about this section:

public function getDb() {
    static $db = null;
    
    if (isset($db)) {
        return $db;
    }
    
    $db = new Db($this->getConfig());
    return $db;
}

If the $db property is set at the beginning of that method to null, won’t it always fail the isset() test that follows and load another instance of the Db class? Would static $db = null; be better placed at the top of the Factory class as a class property? Why is that property static? I thought static properties and methods should be avoided.

Also, I presume what Db($this->getConfig()) is doing is passing in a dependency to the Db class during instantiation, is that right? A dependency within a dependency.

public function getConfig() {
    return new Config;
}

For the above method, it’s creating a Config object each time called. Do I need to create a new Config object each time, or, like the Db object, can I create it just once and simply return it? The Config object mostly holds a bunch of properties with getters and setters that won’t really change throughout the running of a script.

One more question…

public function getBlogController() {
    return new BlogController(
        $this->getBlogModel(),
        $this->getTemplateEngine()
    );
}

I see you are passing BlogController() two parameters that are functions. Are these supposed to be dependencies? Where do these functions exist, within Factory or within BlogController?

This comment on that YouTube video I linked to above accurately describes how I’m feeling.

Thanks again for all your help!

No, because initialization of static variables happens only once regardless how many times the method or function is called. So when you assign the Db object to the static $db variable this variable will retain its value the next time this method is called.

Generally yes, but as in everything in life they also have their legitimate purpose in certain cases. One way of achieving caching is through static variables and this is what I’ve done in my example. I can achieve caching without static variables:

class Factory {
    private $config;
    private $db;
    
    public function getConfig() {
        if (isset($this->config)) {
            return $this->config;
        }
        return $this->config = new Config;
    }
    
    // in some cases you want to always have the same and single
    // instance of a class:
    public function getDb() {
        if (isset($this->db)) {
            return $this->db;
        }
        
        return $this->db = new Db($this->getConfig());
    }
}

You asked about Config returning a new instance each time so I changed it to return the same instance each time - you see, if you have a centralized place like a Factory (or DIC) to instantiate your objects its easy to change instantiation logic because it is done in one place so there is just a small piece of code to adjust. Imagine you are instantiating an object with the new keyword scattered all over your application and one day you decide that you want to force only one instance instead of many or vice versa, or you simply need to change the arguments, - then it becomes a much bigger task.

What’s the difference between caching with a static variable vs private property? Private property is contained within the instance of the Factory class so if you have many instances of Factory then each of them will have its separate cache so it would be possible to have multiple database connections, one for each Factory. A static variable is global across all Factory instances so even if you have many of them the database object will always be the same instance. For a typical application there is no need for more than one Factory instance so it doesn’t really matter. But yes, I might have chosen a too extreme caching method, I would go for the private property method by default unless I had a real need for a much more global static caching.

The thing is that using a static variable like this in the Factory is not harmful because it is just a caching method and if you need to change it then it’s easy to modify the code in a minute. And the static variable is local to one method only. It’s a different thing when you base your classes on static methods - then you begin to see the problems that were described in the article I linked to.

Yes, these are dependencies and getBlogModel and getTemplateEngine would be defined in the Factory. But the idea is when you write your BlogController you don’t worry at this stage about how the dependencies will be constructed, you just require them:

class BlogController {
    private $blogModel;
    private $templateEngine;
    
    public function __construct(BlogModel $blogModel, TemplateEngine $templateEngine) {
        $this->blogModel = $blogModel;
        $this->templateEngine = $templateEngine;
    }
    
    // ...
}

Then you decide how to construct it. You can do it manually in the dirty way, or you can use your Factory, or you can use a DIC.

Good video, simple and to the point.

This is not as difficult as all the terminologies suggest - dependency injection is simply requiring objects in the constructor. Factory is a class that instantiates objects. Dependency injection container is like an automatic factory and is fully optional.

2 Likes

Ah, I completely overlooked that behaviour. Very good to know. So, there is a use for static properties after all! :slight_smile:

Thanks so much for the detailed explanation, and the Factory example. I will start putting it into practice and see how it goes. When searching for “dependency injection” I found an interesting video by a guy named Yegor on YouTube:

It’s a long video (one hour), but I’ve watched this and a few of his other webinars and find some of his concepts pretty interesting. Some of his ideas are either over my head or seem a bit extreme, he’s got very strong opinions about OOP. But overall, I’ve found his videos enlightening and helpful so far.

Thanks again for your input and help with this! I’m sure I’ll be back with a few more questions once I get back to programming instead of watching videos and reading about OOP as I’ve been doing for the past few days.

I must admit he got me interested by the provoking title and watched this video. In my opinion he is very knowledgeable and he has really grasped the concept of OOP, that’s why he might appear extreme to some people. But we need to be practical as well - I’ve done some programming in Java and in that language it is much easier to achieve OO purism, however in PHP it’s more difficult because many aspects of PHP remain procedural at the core, for example primitive types like strings are not objects, a huge collection of procedural functions, etc. Also, in Java sometimes it seemed a bit too much to have to instantiate a bunch of objects and wire them together with another object just to do a simple thing, like format a number or string, whereas in PHP I can use a single function to do the same thing. Here we go into the area of personal preferences so I don’t want to say which way is better.

His idea of not using a DIC but instantiating the application object with a large constructor is good from the OOP perspective but we need to consider he is talking about Java. When you instantiate an object with hundreds of other objects as dependencies you are actually instantiating all those hundreds of objects and they are stored in the memory. It is usually not a problem for a desktop application to load a few seconds before you can use it. But in PHP you initialize your application with every page request and it gets lost a fraction of a second later. Instantiating all application objects every time may quickly eat your server resources, especially if you need to serve tens or hundreds requests per second. So we usually want to instantiate only those objects which are needed and with this task a container (like a factory or DIC) can help - then depending on what a page request is supposed to do the application picks the needed objects from the container and executes proper methods.

Also, I think good dependency injection containers in PHP are a bit different from what he says is used in the Java world. It is not a map of objects but for the most part a clever mechanism that will infer the dependencies from the constructor parameters and create the objects, for example this same class as earlier:

class BlogController {
    private $blogModel;
    private $templateEngine;
    
    public function __construct(BlogModel $blogModel, TemplateEngine $templateEngine) {
        $this->blogModel = $blogModel;
        $this->templateEngine = $templateEngine;
    }
    
    // ...
}

The container by using reflection knows that the necessary dependencies are BlogModel and TemplateEngine and can therefore create them automatically. So when you need an instance of BlogController you only need to do:

$blogController = $container->getInstance('BlogController');

and the container will do its magic and instantiate the object and you don’t have to define your own method to instantiate BlogController like we had to do when using a factory.

Personally, I haven’t used a DIC apart from the simplistic Pimple. I prefer a container in the form of a factory like I showed in my previous post. It may be slightly more work to write a method to instantiate a new object every time it’s needed but it’s really not much work and the advantage is the code is less magical, it’s clearer, I get IDE hints and gain a bit of performance. Anyway, the majority of your application should not deal with the container at all - it should use DI to require objects. The container is just used in the outer shell of your application to instantiate needed objects and then you don’t use it at all and you don’t pass it anywhere else. I think the deleted guy in this reddit thread has a point here.

The interesting thing I’ve observed in OOP that may seem daunting at first is that OOP solves a bunch of big problems but introduces a bunch small problems and then people invent solutions to these small problems, mostly trying to automate things in the long run. Like in this topic, when using static methods we don’t have to instantiate objects so naturally we don’t have a problem with that. Then we start using OO with DI, which helps a lot with the code readability but then we come up with a problem of object instantiation. So we invent a factory and use that. Then we think that maybe there’s too much manual work with the factory so we invent a DIC, which automates most of what the factory does. And it goes on and on. Large frameworks will often implement many of such tools automating frequent tasks and lessening the required amount of code to write and these tools may often require configurations in XML, yaml, or whatever, or PHP annotations or require us to follow some other set of conventions.

But each of such automation solutions comes with a drawback - it increases complexity (even if it’s hidden) and requires the programmer to learn specific framework configurations and conventions to be able to write and understand the code. This matter is purely subjective and every programmer may have different opinions on how far such solutions are helpful.

Personally, I favour code readability over succinctness. I prefer to read and write a bit more code that is immediately obvious what it does rather than have a code as short as possible but have to spend some time learning how to follow it. That’s why I think a full-fledged DIC does not bring enough benefits when I contrast it with how small a problem it solves relative to a factory but at the same time brings some hidden magic to the code - and a DIC also needs a bit of configuration so it not a fully automated thing. I think good code is code that a strange programmer can easily follow without knowing my framework and without having to read any documentation.

2 Likes

Yes, I’m learning that PHP cannot do some of the things Java can do when it comes to OOP programming, which is why I’ve watched a bunch of his webinars mostly for OOP concepts. And I agree with you about the huge memory requirement of instantiating all those objects as he shows in that video. It’s unrealistic for web pages that need to load in 1 or 2 seconds. I only load what is needed to run the script.

I am in agreement with you on this 100%. Less “magical” code is a lot easier to debug, test and come back to months later and remember what’s going on, especially as the application grows, IMO. I try my best to adhere to this principle and not over-complicate the code. This is why I don’t use or like PHP frameworks and prefer to “roll my own” if I can so I know what is going on in the code and don’t have to learn new syntax or conventions to incorporate them into my application. The one exception I make is Smarty for templates. I tried making my own template rendering code, became too complicated and messy.

I like what he has to say, too. Although I don’t understand a few things he says, like this…

Make methods protected or private, except for the 2-3 dependencies you want to fetch at your application root.

Is he talking about the methods that instantiate objects? If so, I don’t understand how this would work, how do you call the method to instantiate an object if it’s protected or private?

protected $sql; function sql() { return $this->sql ?: $this->sql = new Sql(...); }

Is the above code he posted PHP? I’m not at all familiar with that kind of conditional return statement. Maybe that’s only possible in PHP 7? I’m still on old PHP 5.4.

I recently watched this video by Yegor in which he talks about constructors, which was quite interesting.

He essentially says all classes should be small and only have 2-4 public methods max, but can have as many constructors as you want. He notes that PHP doesn’t have the ability to have more than one constructor per class and that you can achieve something similar by passing an array of parameters upon instantiation that your constructor then acts on to create the object. This was actually an idea I had in another thread, but I was discouraged from that approach. But I still like this idea because you don’t have to remember the order of parameters to pass in dependencies, for example, and can pass in other options for instantiating the object as well.

I’m thinking of taking this one step further by using a Params object that would hold all the parameters for an object, including dependencies, and a few basic methods for getting and setting those parameters. Then I’d inject the object with this Params object. This is a quick and dirty example of the Params class:

class Params
{
	private $params = array();

	function __construct() { }

	public function set($pname, $pvalue='')
	{
		$this->params[] = array($pname => $pvalue);
	}

	public function get($pname)
	{
		if (!empty($pname)) {
			// Get a single parameter
			if (isset($this->params[$pname])) {
				return $this->params[$pname];
			} else {
				return null;
			}
		}

		// Return ALL parameters if one not specified. 
		return $this->params;
	}
}

Then I would use it like this…

$site_p = new Params;
$site_p->set('db', $db);
$site_p->set('config', $config);
$site_p->set('id', 999);
// Inject Params into object 
$site = new Site($site_p);

The above code could go into my Factory “container” thingy we’ve been discussing. The Site constructor would know what to do with these parameters…

class Site 
{
	private $params;
	protected $db; // Dependency
	protected $config; // Dependency 
	protected $id = null; 

	function __construct(Params $params)
	{
		$this->params = $params;

		$this->db = $params->get('db');
		$this->id = $params->get('config');
		$this->id = $params->get('id');
	}

	// ... rest of class ... 
}

There would of course be some validation and error checking code in the constructor, too, to be sure valid parameters were passed and throw an exception if not. I still think this would be a lot easier and cleaner than having to do something like this:

class Site 
{
	protected $db; // Dependency
	protected $config; // Dependency 
	protected $id = null; 

	function __construct(DB $db, Config $config, $id)
	{
		// ...
	}
}

I don’t have to remember the order of the parameters, and have a lot more flexibility in how objects are instantiated. What do you think?

I’m also rolling my own PHP framework and CMS and use the factory pattern and reflection to instantiate data models, components, modules, even page objects. This can ease the accessibility of different object instances and data throughout your application preventing running duplicate tasks and instantiating objects more than once. For example some factories will have a method called getInstance that will return an instance of a type of object. If this instance doesn’t exist it will create one and store it in an array and if it does it will simply return it. Factories also can ease the handling of dependency injections and the consistency in which you use them throughout your application classes.

I find that a very useful pattern in OOP is composition coupled with inheritance. I have some times heard developers debating on which one is better but I think they are most powerful when used in combination. If you then add the factory pattern on top you can have something very powerful.
For example my components are instantiated by a factory that will look for file overrides for those base components. It might find a class file override that extends the base component and implements it in a custom way, so it creates an instance of that class instead and returns it. The factory does all the heavy lifting like including files, looking for extensions, taking care of conventions, error handling, instantiation …

IMHO for me Smarty is overkill. A template engine can be as simple as the following code:

	public static function template($file, $vars)
	{
		$rv = "";
		if (is_array($vars)) {
			foreach ($vars as $name => $val) {
				$varName = $name;        
				$$varName = $val;
			}
		}
		if (file_exists($file)) {
			ob_start();
			include($file);
			$rv = ob_get_clean();
		} else {
			throw new Exception("Invalid template file given: ". $file);
		}
		return $rv;
	}

I do not think so. IMHO It is a lot easier to know what’s going on in the latter example, and reduces complexity. But then I would suggest once again that if you have a lot of config parameters you allow that config to be set through public setter methods as well. Because you have more control over the input and validation of those parameters and also even though more verbose it is a lot more clear what the code is doing and what is expected to happen. Then you can also have a method called configure if you like that loops through all those config parameters and looks for a setter method ‘setConfigParameter’ and call it if it exists. That is how I do it anyways for heavy duty objects…

Just looked this up. My gosh, I have so much to learn. I guess I am mostly using composition, because I’m not completely sure how inheritance is implemented in PHP. Is that done with extends? Haven’t used very much of that yet.

I thought Smarty was overkill at first, too. But for this system I’m working on, templates may be provided by outside sources, so, I didn’t want a template system that used direct PHP for security purposes. Smarty solved that, and has a fairly easy-to-understand syntax. So for my needs, Smarty was better than rolling my own.

Yes, I know, every time I’ve mentioned this method of passing parameters to functions on a coding site no one ever seems to like it. :slight_smile: But one thing I’ve always hated about functions is that you have to pass all parameters in a particular order.

function func ($db, $config=null, $id, $type=null, $css=null, $err=null) { }

func ($data, '', 999, '', '', "Required Field"); 

To me this is cumbersome and requires constantly looking up the function to see what order the parameters must be passed when it’s easier (for me) to do this:

function func ($params) { }

func( ['db'=>$data, 'id'=>999, 'err'=>"Required Field"] ); 

What I like about this approach is that this also works:

doThis( ['id'=>999, 'db'=>$data] ); 

I just pass the parameters I need in any order and the function takes care of the rest. I find it easier to remember the parameter name rather than the order of each parameter. I know this doesn’t make clear what options the function needs, but I put all that in the comment block for the function, so it’s easy to figure out. This approach has worked well for me for many years, which is why I may adopt it for injecting parameters and dependencies to objects. Because for some objects I’ll have 4-6 dependencies in addition to a few parameters, and want the ability to instantiate the object with all of that in place.

That’s actually what I do. Most of the config options passed into the object as an array will use private setter methods to handle each parameter. I’ll only make those setter methods public if it’s a property that should be mutable after the object has been created.

However, when you are beginning with OOP concepts it is very beneficial to learn to use a framework because you can learn a lot - you will gain practical experience and first-hand see solutions you would never come up with on your own. Sure, some of the solutions you won’t like or will seem not useful whereas you will like others. But you will see how the “big guys” structure PHP applications and you will build your own opinions. I would suggest you look at the major PHP frameworks, see some code examples and decide which style you like best, pick that and develop at least one application based on that framework, configure it to your requirements, inspect the code and see how certain problems are solved, experiment, etc. After that you will be in a much better position to roll your own framework that will be of quality for you for years.

protected $sql; function sql() { return $this->sql ?: $this->sql = new Sql(...); }

This is identical to the property caching mechanism I showed you in the factory example, except it uses a pretty old ternary operator instead of if...else.

You call protected or private methods from the same (factory) class. He suggests to have one method for instantiating each object. But certainly, you won’t need every object to be available publicly on your factory because some objects will only be required as dependencies to other objects. A common example is the database connection - the code that runs the main part of the application (like a router) will not do any operations straight on the database but will execute a method that does a certain task and that method will use the database as a dependency. So your factory (or container) may look like this:

class Factory {
    private $db;
    
    public function getSalesReport() {
        return new SalesReport($this->getDb());
    }
    
    public function getPurchaseReport() {
        return new PurchaseReport($this->getDb());
    }
    
    private function getDb() {
        if (isset($this->db)) {
            return $this->db;
        }
        
        return $this->db = new Db($this->getConfig());
    }
}

Here you will be interested in using SalesReport or PurchaseReport to generate reports so you need to fetch those objects and run a method on them (e.g. in the router). However, getDb can be hidden because you will not need its instance directly when running those methods.

Why is arbitrary order of parameters so important to you? You presented your solution to the problem so instead of saying if it’s good or bad let’s consider its advantages and drawbacks.

Advantages:

  1. No need to remember parameters’ order.
  2. Shorter list of parameters to pass to the constructor when the class requires many dependencies.

Disadvantages:

  1. You have to remember parameters’ names.
  2. You have to write your own code to check whether all required arguments are supplied and they are instances of proper classes.
  3. It is not immediately obvious what parameters are required and which are optional unless you consult your comments.
  4. You have to write and maintain more code just to deal with parameters, especially so if you use a Params class like you presented above.
  5. Slower in performance.

And to this let’s remember that PHP has built-in support for passing parameters whose only drawback is that the order is fixed. But it has other advantages:

  1. No need to write any code for that so at the same time it’s less work and less chances for errors.
  2. Clearer - type hints in parameters are immediately obvious what objects are required, you don’t even need comments for them but of course you can supply them.
  3. Self-checking by the PHP engine.
  4. All IDE’s give you immediate hints about the parameters so you don’t really have to remember their order nor jump to the comments at their declaration. Are you using an IDE? If not, you should really give it a go :smiley:
  5. Very fast.

And the built-in mechanism offers enough features for most cases:

  1. Optional dependencies can be required via optional parameters in the constructor or be supplied using setter injection.
  2. A type hint can require an interface instead of a specific object as a dependency, which means you don’t need to pass any one specific object - you can supply any that adheres to the same API but can do different things. This allows you for quite a bit of flexibility. So read about interfaces :slight_smile:

Everyone needs to judge for themselves which method they prefer but to me, given the above conclusions, passing dependencies in an array or a params object does not offer enough benefits and brings more problems than it solves, especially that PHP offers a pretty good alternative with its native features. To me this is what I would consider overcomplicating things too much and I much prefer the simpler and native solutions. Perhaps that’s why most people are not fond of your idea? :slight_smile:

Moreover, we should strive to make the dependency list as short as possible. If there are too many dependencies it may be a sign that the class has too many responsibilities and it’s a good idea to break it into several components. With few dependencies the parameter list is short and not much problematic. But even in rare cases when you really need a long list of dependencies I would still prefer to keep it simple and just require all of them in the constructor. If the list looks too cluttered then simply split them into separate lines for visual clarity!

Also, we need to put things in perspective - in a typical application object instantiation is something that is usually restricted to one place - the container. So it’s not like you spend most of your time needing to write new something(...) - in proportion to other things you do it very occasionally and if you have a reflection-aware container you don’t even have to write it at all. So even with a theoretically the best possible solution to arbitrary parameters order the final benefit remains pretty minor.

A Params class like you presented might have some good use if you needed to encapsulate a large collection of config parameters or re-use the config in many places but it’s not something I would choose by default as my dependency injection method. For me, it’s just overkill.

2 Likes

This isn’t really an option for me as I’m trying to update a large legacy PHP application. Going to a framework will mean starting from scratch and learning that framework, which I can’t afford (in time) to do right now.

Oh! Okay, I’ve used that but never in a return, and I didn’t know about the ?: option before because I was using an older version of PHP that didn’t support that.

Ah, now I understand, thanks.

Ironically, this is why I have more dependencies, because I’ve broken down some classes into smaller classes with fewer responsibilities. Many of my “module” classes will need 3-4 dependencies, and some will need 4-6. I don’t really see a way to break those module classes down further. Just to do one database query will require objects for DB, Config, Site and Prefs, for example. So I can’t really avoid that unless I combine a few of those dependency classes. But then I’m back to having classes with too many responsibilities which is where I started. Seems to be a Catch-22 with this.

So, I think I’m just going to stick with classes as they are written and just have a long list of parameters to instantiate each of the objects that depend on them. Which is why I am considering my workaround of injecting just one Params object into other objects that need dependencies and other parameters. However, you have made some very good points about why that is such a terrible way to do things, which I will definitely consider and weigh.

Yes, I’m using Sublime Text 3. But it doesn’t show me all options for my custom functions as I type it out, it only does that for PHP built-in functions. Perhaps I’m missing something about how this is works in Sublime Text.

Question: When using a factory container, do I load the actual class files within that container or outside the container from the main, calling script? I’m presuming the latter, but just want to be sure.

Thanks again for all your advice!

Of course, it doesn’t make sense to rewrite an existing system but if you get a new project in the future you may consider this. Even making a simple web site with a new framework offers a lot of learning.

Wait, something here doesn’t sound right - are you saying that the smaller classes you have the more dependencies they require? This appears to be contrary to any logic - maybe you could share some piece of code because we might be using same terminology for different things.

This might be the curial part - why do you need so many objects to do one database query? To do a database query it is enough to have just one object and you can use it to execute as many queries as you like. So your small class that does one database query needs just one dependency - the database object. How did you come to the conclusion that you need more?

Sure, the database configuration may be in a Config object but that doesn’t mean you need that object in your class. The database object might need Config but your class does not (and should not) care about it. Neither about Site and Prefs unless this class has a specific aim to deal with Site and Prefs directly.

I don’t know Sublime Text very well but I think it does not belong to the IDE category, I think it’s more an advanced source code editor. But maybe you could add some IDE functionality with plugins. An IDE scans all the code in your project and has knowledge of the types in your variables, arguments, etc. and can offer you many useful hints, code auto-completion and can highlight errors that a normal editor would not be able to detect - much more beyond syntax errors.

You mean require_once? I think the most logical place for that is just before calling new Object... because this way you load only required files on demand. However, a much better way would be to use an autoloader and then you can forget about loading files because it is done automatically. If you use Composer it offers you a pretty good autoload class that will lift the whole burden from you.