Reputation: 1005
I am creating a very basic application framework for my project that uses the standard MVC approach and has support for modules (which I'm calling apps). There are a number of global objects created like $URI, $ROUTER, $PROFILE,
etc. and access to global libraries like Array Helpers and Calendar generators. All of it is similar to Codeigniter or FuelPHP and any number of other frameworks, but we wanted something specific to our needs and decided to go from scratch (borrowing and modifying some libraries from the above).
My question is this. If one module loads the Calendar library, and the Calendar Library has no need for constructor variables or dependencies (i.e. every new \Calendar
) will be identical), is there a way to ensure that only one calendar object is created? So if Module 2 tries to create a Calender Object that Module 1 has already created, the system would deliver the same object. I should clarify that multiple modules can run at once (why we needed a new framework).
I've heard terrible things about singletons and haven't been impressed with factories (which I may not be using correctly).
What is best practice?
Thanks!
Upvotes: 0
Views: 380
Reputation: 1836
What if you used a session flag?
if(!$_SESSION['calender']){
$calander = new Calander();
$_SESSION['calender'] = true;
}
Would this work for you?
Upvotes: 1
Reputation: 57729
What you'll want is something like a service container. Like:
$server_container->add_service("my calendar", "Calendar");
Then any module that needs a calender (or "my calendar"
in specific) can be constructed with:
$mymodule = new MyModule($service_container->get_service("my calendar"));
class MyModule {
public function __construct(Calendar $calendar) { /*..*/ }
}
Singletons are bad because it makes your code untestable. With code like the above you can replace $calendar
by a stub that implements Calendar
. Proper DI would argue that you need a CalendarInterface
too but you might have dependencies that don't allow you to make that distinction.
Upvotes: 0
Reputation: 13933
How about an inversion of control system? You could make a global IOC object that has instructions for creating an object, but that also has a registry that contains references to already created objects. In the registration portion of the module for each item that you want to behave "singletonny", you simply check to see if it's already been instantiated. The only other option I can think of is that since you aren't looking to construct anything, make it a static class that you can't instantiate and access the class statically (Calendar::printSomeFunction). I am not, however, opposed to the singleton pattern, for what it's worth, when it's used correctly. I just choose more elegant solutions such as #1 here, because it is very flexible. You don't however have much control over whether or not a dev creates a class outside of the IOC module so you might consider protecting that in some way. Hope that helps your decision making process.
Upvotes: 1