I need to develop a small CMS using PHP, and right now I'm trying to figure out the structure.
The CMS will be generated using a set of functions. Things like database functions, caching thingies, internationalization and stuff like this.
I was thinking to do it like this:
make the functions non-static methods part of a big "site" class; that way I could run multiple instances of that class. Not sure I would need to do that though..
or split the functions into separate classes with static methods
The main problem here is that the CMS should be able to manage multiple small sites, not just one. So either I make all methods static and add a "site switch" function, or make them normal objects which I instantiate based on the site which I want to manage
Which of these would be the best option?
Static methods are generally bad practice. They introduce a lot of potential issues.
1) They introduce hidden dependencies. Code which arbitrarily calls foo::bar() has a dependency on foo and cannot run without foo being defined. The object using foo::bar() will construct correctly but won't be usable if foo is not defined.
2) Statics are globals. Global state is very bad, anything can change the code and its state is unknown. You sacrifice the power and control achieved by OOP encapsulation by using static methods.
3) It's impossible to substitute the functions for a different version
4) It makes unit testing impossible.
For more detailed information and code examples, see this article and this article
I'd definitely suggest using static classes for this job. Going this route will create a pseudo namespace for all of your functions so you don't have to worry about conflicting function names, etc, and it also prevents you from having to pass around an instance of your helper class just to call one of your helper functions.
Related
In my example I'm using the PHP framework Yii2 but I think this applies to most OO languages.
I have an ActiveRecord base class which most of my business objects extend from e.g. Project.
At the moment if I want a Project instance I call
Project::findOne(['id' => $id]);
findOne is a static method of ActiveRecord (which is part of the Yii2 framework). So this is bad form because I can't easily mock/stub the return of this call when writing unit tests.
But what's the best way to get around this?
I could create a class CActiveRecord that inherits from ActiveRecord and wrap the static call in a non-static call and use that everywhere - but then I would have to instantiate a throw-away Project object in order to get the actual instance. What if the Project object needed some heavy config to be instantiated - I would be passing random nonsense into the constructor just to get an instance.
Summary:
Simply changing statics to non-statics seems wrong - shouldn't I also move the functions somewhere else? If so, where?
The issue with static calls is the hard coupling to a specific other piece of code. Just wrapping that in a "dynamic" call doesn't make this any better:
$c = new CProject;
$c->findOne(); // Calls Project::findOne()
That's pretty darn pointless. The issue is not the syntax of -> vs. ::, the issue is that this particular code references a specific other class and that you cannot easily exchange this class for something else. You're building rigid, hardcoded dependencies between your classes/objects, which makes it hard to take them apart, which makes your code hard to test, and which makes it harder to adapt code to different situations.
The alternative is dependency injection:
function foo(Project $project) {
$p = $project->findOne();
}
This function is not coupled to any one specific Project class, but to a class which simply offers an interface akin to Project. In fact, Project could even be simply an interface. Which specific class and method is getting called here then is decided somewhere completely different, like your dependency injection container; or simply the caller of this code.
This makes it a lot easier to take this code apart and put it back together in different ways, as necessary for the situation at hand. That's not to say it can't work and that you should never use static calls at all, but you really need to be aware of what cross-dependencies you're establishing with every hardcoded class name, and whether that may or may not cause a problem down the line. For even moderately complex and/or growing software projects, it will almost certainly cause friction in some form or another eventually.
See How Not To Kill Your Testability Using Statics for a longer in-depth article.
In my example I'm using the PHP framework Yii2 but I think this applies to most OO languages.
I have an ActiveRecord base class which most of my business objects extend from e.g. Project.
At the moment if I want a Project instance I call
Project::findOne(['id' => $id]);
findOne is a static method of ActiveRecord (which is part of the Yii2 framework). So this is bad form because I can't easily mock/stub the return of this call when writing unit tests.
But what's the best way to get around this?
I could create a class CActiveRecord that inherits from ActiveRecord and wrap the static call in a non-static call and use that everywhere - but then I would have to instantiate a throw-away Project object in order to get the actual instance. What if the Project object needed some heavy config to be instantiated - I would be passing random nonsense into the constructor just to get an instance.
Summary:
Simply changing statics to non-statics seems wrong - shouldn't I also move the functions somewhere else? If so, where?
The issue with static calls is the hard coupling to a specific other piece of code. Just wrapping that in a "dynamic" call doesn't make this any better:
$c = new CProject;
$c->findOne(); // Calls Project::findOne()
That's pretty darn pointless. The issue is not the syntax of -> vs. ::, the issue is that this particular code references a specific other class and that you cannot easily exchange this class for something else. You're building rigid, hardcoded dependencies between your classes/objects, which makes it hard to take them apart, which makes your code hard to test, and which makes it harder to adapt code to different situations.
The alternative is dependency injection:
function foo(Project $project) {
$p = $project->findOne();
}
This function is not coupled to any one specific Project class, but to a class which simply offers an interface akin to Project. In fact, Project could even be simply an interface. Which specific class and method is getting called here then is decided somewhere completely different, like your dependency injection container; or simply the caller of this code.
This makes it a lot easier to take this code apart and put it back together in different ways, as necessary for the situation at hand. That's not to say it can't work and that you should never use static calls at all, but you really need to be aware of what cross-dependencies you're establishing with every hardcoded class name, and whether that may or may not cause a problem down the line. For even moderately complex and/or growing software projects, it will almost certainly cause friction in some form or another eventually.
See How Not To Kill Your Testability Using Statics for a longer in-depth article.
I'm working on an app, and part of functionality of this app is that it is extendable through addons.
The main app uses has a Render class that contains a lot of static methods that have to do with output. The actual methods interact with models/views, but the basic idea is that the Render class encapsulates methods that render something, like:
// To output "hello"
Render::sayHello();
// To output a picture of a cat wearing a hat
Render::catWithHat();
Now, from time to time addons require their own unique output functions. These output functions are very similar to the Render methods. So...
My first thought was that it would be great if I could dynamically add methods to the Render class, but after reading up about on-the-fly method creation it sounds like that's generally not considered very good practice.
So then I thought, well, I could just not encapsulate the addons' render functions at all. So that you'd just call them like:
renderMyAddonOutput();
I don't love that idea either, though.
So I guess I'm just wondering what would be considered best practice for encapsulating related functions that are declared across a variety of files.
Thoughts?
Note: if it makes any difference, I'm using Laravel for this (the very latest version).
I would consider using a Plugin pattern where an add-on registers itself into some kind of static container on init, and then you can use PHP's magic method __call() or __callStatic() to check the plugin array when a method is called that isn't found in the base class..
So if you had:
Render::pluginMethod()
then __callStatic() would check your plugin registry (which can be as simple as a static array of plugin classes or methods) and if it finds that method, it calls/returns it.
This might be a stupid question but I have to ask:
I have a big group of related functions for a project I am doing. The functions need to access a few global variables, so I was thinking about putting them into a class and loading the class as needed. I suppose my other option is to just include them as unrelated functions in an included PHP file, but putting them into 1 class seems to make sense. Is this an acceptable practice? I have worked with people who did this but it always seemed to not quite be in the spirit of good OOP practices because the classes were almost never instantiated but the functions were still called. Or maybe I'm over thinking it.
Any input would be awesome, thanks a bunch.
A class does make the most sense. Whenever you can eliminate global variables, it is a good thing. Whether the class is instantiated or a static helper usually depends on the context. However, for future unit testing, instantiations allow dependency injection.
According to http://en.wikipedia.org/wiki/Class_%28computer_programming%29, a class defines constituent members which enable class instances to have state and behavior. If you will be providing only behavior (functions) and not state (properties), you should include your functions in an include file and forgo the overhead of a class.
Correct me if I'm wrong but this seems like you should create a class that acts as a static service, where no explicit instantiation is needed of the class, yet you will still call the methods contained within this class.
Now, if you're thinking of storing those global variables in the class, obviously that's no longer a static class because there would have to be some sort of lifetime for the object, and at which point you'd have to instantiate the class first and then make calls to those methods.
Regardless, if they're all related functions working on the same data, it certainly makes sense to group them within their own class.
In a theoretical database access class, I found that there are quite a few helper functions that I use in the class, which have nothing to do the class's instance (and others, that could be manipulated to be unrelated to the class's instance using dependency injection).
For example, I have a function that gets a string between two other strings in a variable. I've been thinking of moving that to a String_Helper class, or something of the sort. This function has already been made static.
Also, I have a function that queries a database, query($sql). The connection details are provided by the instance, but I've been considering making it static, and using query($sql, $connection). Developers would then be able to call it statically and not need to instantiate the database class at all.
For me, the questions are:
Is it worth it to do something like this? Functions like the query function make me wonder if this is not just me trying to make everything as static as possible, without any real need to. Under what circumstances would you consider this useful?
I know static functions are harder to test, but if I make sure that their code is completely dependency free (or uses dependency injection where necessary), then they're just as easy to test as everything else, surely?
It isn't a concern at the moment, but if, in the future, I decided to extend the classes with the static functions, it would be impossible for me to make the current code use my extended functions. I've thought of Singletons, but the same problem arises: the code would be calling Singleton_Class::getInstance(), and not My_Extended_Singleton_Class::getInstance(). Dependency Injection seems to be the only way to solve this issue, but it might lead to a clunkier API, as every dependency has to be given to an object on __construct().
I have a container class, which holds certain pieces of information statically so that they can be accessed anywhere in the script (global scope). If I can't use static functions or singletons, a class that contained instances of different variables would be great. One could use for example Container::$objects['MyClass'] = $MyClass_object;, and then the rest of the code could just access Container::$objects['MyClass']. If I extended the MyClass class, I could use Container::$objects['MyClass'] = $MyExtendedClass_object;, and the code that used Container::$objects['MyClass'] would use MyExtendedClass, rather than MyClass. This is by far the best way to do it, in my opinion, but I'd like to know what you think about it.
Ok, let me answer these one by one...
1. Is it worth doing something like this
Yes and no. Splitting out the helper functions into their own classes is a good idea. It keeps the "scope" of each of the classes rigidly defined, and you don't get creap. However, don't make a method static just because you can. The query method is there to make your life easier by managing the connection, so why would you want to lose that benefit?
2. They are harder to test
They are not harder to test. Static methods that depend on state are harder to test (that access static member variables or global variables). But static methods in general are just as easy to test as instance methods (in fact, they can be easier since you don't need to worry about instantiation).
3. Extending the classes
This is a valid concern. If you put String_Helper::foo() in the class itself, you'll run into issues. But an option would be to set the name of the string helper as a class variable. So you could then do {$this->stringHelper}::foo() (note, PHP 5.3 only). That way to override the class, all you need to do is change the string helper class in that instance. The Lithium framework does this a lot...
4. Global Registry
I would stay away from this. You're basically just making every class a singleton without enforcing it. Testing will be a nightmare since you're now dependent on global scope. Instead, I'd create a registry object and pass it to classes via the constructor (Dependency Injection). You still accomplish the same thing since you have a store for the objects/classes, but you're no longer dependent on a global scope. This makes testing much easier.
In general
When you're looking at doing things like this, I like to stop when I hit questions like this. Stop and sit down and think *What actual problem am I trying to solve?". Enumerate the problem explicitly. Then pull our your supposed solutions and see if they actually solve them. If they do, then think about the future and if those solutions are really maintainable in the long run (Both from a bug fix standpoint, and with respect to feature additions). Only if you're happy with both of those answers should you even consider doing it. Oh, and also remember to keep it simple. Programming is not about making the most complex, most clever or most amazing solution. It's about making the simplest solution that solves the problem...
I hope that helps...
Good Luck!