To be clear, I don't want to instantiate the same class multiple times. I only want to instantiate it once, and keep track of any changes made to that instance via some reference. Is this possible, and if so how can it be done? Thanks!
You can use the Singleton pattern for this. The PHP manual has a good example and description:
The Singleton ensures that there can be only one instance of a Class and provides a global access point to that instance.
Class:
<?php
class Example
{
private static $instance;
private function __construct() {
}
public static function singleton() {
if (!isset(self::$instance)) {
echo 'Creating new instance.';
$className = __CLASS__;
self::$instance = new $className;
}
return self::$instance;
}
public function __clone() {
trigger_error('Clone is not allowed.', E_USER_ERROR);
}
public function __wakeup() {
trigger_error('Unserializing is not allowed.', E_USER_ERROR);
}
}
Usage:
$singleton = Example::singleton();
It is worth also noting these objections to the singleton pattern from the PHP manual:
The Singleton pattern is one of the more controversial patterns. Critics argue that
Singletons introduce Global State into an application and tightly
couple the Singleton and its consuming classes. This leads to hidden
dependencies and unexpected side-effects, which in turn leads to code
that is harder to test and maintain.
Critics further argue that it is pointless to use a Singleton in a
Shared Nothing Architecture like PHP where objects are unique within
the Request only anyways. It is easier and cleaner to create
collaborator object graphs by using Builders and Factory patterns once
at the beginning of the Request.
Singletons also violate several of the "SOLID" OOP design principles
and the Law of Demeter. Singletons cannot be serialized. They cannot
be subtyped (before PHP 5.3) and won't be Garbage Collected because of
the instance being stored as a static attribute of the Singleton.
See as well: Who needs singletons?
You can create Singleton pattern
class Something {
private static $instance;
private function __construct() {
}
public static function getInstance() {
if(Something::$instance == null) {
Something::$instance = new Something();
}
return Something::$instance;
}
public function someMethod() {
return "abc";
}
}
When you want to use it you call Something::getInstance()->someMethod()
Read more about singleton pattern.
To be clear, I don't want to instantiate the same class multiple times. I only want to instantiate it once, and keep track of any changes made to that instance via some reference. Is this possible, and if so how can it be done? Thanks!
Sure this is possible. You can do this literally:
First of all, as you don't want to instantiate the class multiple times, just instantiate it once:
$instance = new Class();
Then you want to keep track of changes made to that instance. I don't specifically know what you mean. Probably you mean to only keep that one instance. You just can do so, as you have only instantiated once, you can refer to that instance with the $instance variable.
Additionally you can "reference" that $instance as well in some other variable:
$reference = $instance;
You can now access the single instance of Class with the $instance and the $reference variable.
If you need to monitor the instance, I suggest you create a Decorator that does the job:
$decorator = new ClassDecorator(new Class());
The decorator can then work as an interceptor before anything reaches Class.
To find out if the inner state of a class has changed or not, you can make use of the serialize and unserialize functions as well:
$instance = new Class();
$snapshot = serialize($instance);
...
# more code, $instance is changed or not, we don't know
...
$changed = $snapshot != serialize($instance);
Hope this is helpful.
What you are trying to do is called the Singleton Pattern .. See http://en.wikipedia.org/wiki/Singleton_pattern
Related
I have some Legacy classes.
Many classes are instantiated using a Factory Class.
There is also a Singleton-Class.
In the future I want to replace them completely with the DIC.
For the moment the codebase is to large to do this.
Now my goal is to inject the DI-Container into every Service instantiated by the Singleton class.
The Singleton class has a static method with this signature.
final class Singleton
{
private static $singletonCache = array();
public static function getInstance($namespace, $className)
{
}
}
inside of this function I want to check for:
$instance = new $className();
if($instance instanceof ContainerAwareInterface)
{
// TODO: how do we get the container here
$instance->setContainer($container);
}
But how can I best get the container inside of my "singleton class", which is only called statically?
Another approach is to access the container globally when you need it:
public static function getInstance($namespace, $className)
{
$container = $_GLOBAL['kernel']->getContainer();
}
Of course there are sorts of things wrong with this approach but as long as you are transitioning then it's enough to get by.
Somewhere early in your bootstrapping code, but after the container is instantiated, you can pass the container to your singleton class:
Singleton::setContainer($container);
It would store the container in a static property:
final class Singleton
{
// ...
private static $container;
public static function setContainer(ContainerInterface $container)
{
self::$container = $container;
}
}
However, as you learned on the example of your singleton class, all global state gives you is headaches. Passing the container around (and using ContainerAware) is something to avoid. By passing the container to your services you're making them rely on the whole world of services. It's cleaner to only pass collaborator you actually need. It's also far easier to test.
Another solution is presented in this answer, which is pretty much the same as the other answer to this question, just using the global keyword instead of the $_GLOBAL array to access the kernel object.
public static function getInstance($namespace, $className)
{
global $kernel;
$container = $kernel->getContainer();
}
I see these classes quite often but i don't use them in my projects. I was checking these design patters from here and I noted they use static classes
From page above, sample code:
class AutomobileFactory
{
public static function create($make, $model)
{
return new Automobile($make, $model);
}
}
or in Singleton pattern:
public static function getInstance()
{
static $instance = null;
if (null === $instance) {
$instance = new static();
}
return $instance;
}
I'd recommend you read How Not To Kill Your Testability Using Statics first as intro into what I'll talk about below.
The point of a factory is typically to allow dependency injection for methods/objects that need to instantiate other objects. E.g.:
public function foo() {
$bar = new Bar;
}
This is bad, as discussed in aforelinked article. But this method must be able to instantiate a Bar object itself. Yet we still want dependency injection.
Enter a factory:
public function foo(BarFactory $factory) {
$bar = $factory->create();
}
Therefore, a static factory is pretty pointless:
public function foo() {
$bar = BarFactory::create();
}
There's virtually no advantage over directly instantiating new Bar here.
Singletons are a hotly discussed topic and they're often discouraged, for the same reason that global objects are discouraged. Singletons which are statically being referred to are bad again, as discussed at length in the article.
The first example is a factory class. A factory is a piece of code that helps you to create and configure an object. A factory can be a function or method, a static class, or an instantiated class. Usually it is not necessary to instantiate a factory, so static classes are often used for that. But I think a factory might as well be instantiated. Doing that allows you to configure or extend the factory so it gives you even more flexibility over having a single static factory method.
Also, I think in most cases static classes are just an excuse. People often tend to promote global functions or variables to a static class to make 'clean' code, but it provides little improvement. It was a little useful before PHP supported namespaces, but nowadays, I think you should be careful when creating static classes.
The same applies to singletons, although it has its use, because in some cases you want to have only one instance of a class. Examples of this include connection pools, or hardware controllers. Having multiple instances of some object might cause problems, so that's a good reason to use singletons.
But people often make an object a singleton when there is no need. In that case, I think it's just a way to hide the fact that you're using globals, and it's bad practise.
But a singleton is not a static class. It is just a class that hides its contructor and provides a static method to reach the single instance of the class. It is similar, but not the same as a static class.
I can recommend reading Head First Design Patterns. It explains both patterns (and many more) in a fun and accessible way. The code examples lean towards Java, but that's hardly a problem.
These classes have a definite use. Let's take an example of a logger.
class Logger() {
private __construct() {}
public static function getInstance()
{
static $instance = null;
if (null === $instance) {
$instance = new static();
}
return $instance;
}
//other methods here
}
}
Now after instantiating it once you can do something like
Logger::log(parameters)
where log is a method in that class.
That is just one example where such a class is very useful.
I'm trying to figure out the best practices for dependency injection in PHP.
Question: Do I have to inject all dependencies of a subclass into the parent class? I use the terms 'parent' and 'child' in terms of a composition relationship.
My hesitation is because I find myself giving the parent class all kinds of dependencies so that it can just pass them down to dependent child classes.
Edit:
Below is a more concrete example of what I'm talking about. MyClassA does not need the database connection object or the logger. DoSomething does need these objects, however. What is the best way to get the database connection and logger to the DoSomething instance? I don't want to use singleton objects or global objects for the sake of unit testing. Also, this example only uses to classes. What if there are 3 or 4 and the 3rd or 4th needs some object instance but the first 2 or 3 don't? Does MyClassA just pass the object to the next, and so on?
class MyClassA {
protected $_doSomethingObject;
public function doSomething()
{
return $this->_doSomethingObject()->doSomethingElse();
}
public function setDoSomethingObject($doSomethingObject)
{
$this->_doSomethingObject = $doSomethingObject;
}
}
class DoSomething {
protected $_logger;
protected $_db;
public function doSomethingElse()
{
$this->_logger->info('Doing Something');
$result = $this->_db->getSomeDataById();
return $results;
}
public function setLogger($logger)
{
$this->_logger = $logger;
}
public function setDBConection($db)
{
$this->_db = $db;
}
}
Is the best way the example I show below? If so, then the best way is to work backwards so to speak...?
$logger = new Logger();
$db = new DBConnection();
$doSomething = new DoSomething();
$doSomething->setLogger($logger);
$doSomething->setDBConnection($db);
$a = new MyClassA();
$a->setDoSomething($doSomething);
If so, then the best way is to work backwards so to speak...?
Yes. As I mentioned in the comment, you set up the inner most objects first.
If an object create another object internally that isn't exposed, then it could pass along its injected objects if appropriate. For example:
class DoSomething {
// ...
public function foo() {
$foo = new Foo();
$foo->setLogger($this->_logger);
return $foo->bar();
}
}
However, if that secret Foo object needed references to other things that DoSomething didn't have, then you've got design issues. If that happens you need to do whatever is appropriate:
Inject a foo object into the parent object prior to calling foo().
Inject that dependency into the parent object prior to calling foo().
Add the dependency as a function argument.
Refactor code into a better design that doesn't create that problem.
You need only include the dependancies in the classes that are going to directly need them. Since the required/included files will be loaded whenever the base class loads, they will automatically be available to any child classes.
An ethical question here.
I'm planning on using several manager classes in my new project that will be performing various tasks across the whole project. These classes are singletons, but require construction based on parameters.
As to when/where this construction has to happen, I have mixed feelings. I have these options so far:
Option A
It's easy to just pass these parameters to the getInstance method while having a default null value. On the very first call the parameters will be used, and any additional calls completely ignore them.
While this works, doing so feels rather unlogical, for the following reasons:
It makes documentation unclear. getInstance' first parameter must be of type Collection, but can be null... what's going on here?
You can argue that writing a line about this in the description will clear it up, but I'd prefer clarification to be unneccesary.
It feels faulty to pass getInstance any construction parameters. This is due to the fact that the method name does not explicity hint towards construction, making it unclear it will happen.
Option B
I'm thinking about a setup method. This method takes all parameters, calls the class constructor, and changes the internal class state to initialized.
When calling the getInstance method prior to setup, it will throw a NotInitializedException. After setup has been called, any additional calls to setup will result in a PreviouslyInitializedException.
After setup has been called, getInstance becomes available.
Personally, this option appeals more to me. But it feels excessive.
What option do you prefer? And why?
I would probably try and ditch the singleton approach and pass manager classes around to whatever needs them.
$manager = new Manager( $collection, $var, $var2 );
$other_class = New OtherClass( $manager );
//or
$other_class = New OtherClass;
$other_class->manager = $manager;
//or
$other_class = New OtherClass;
$other_class->setManager( $manager );
Use dependency injection to pass the Manager object around. Don't use Singleton pattern. It's a common consensus that using it creates a global state and makes your API deceptive.
PHP Global in functions (jump to answer)
Singletons are pathological liars
Inject the Manager instance to any class that needs it via the constructor. Each class should not try to instantiate Manager by themselves, the only way the classes get an instance of the Manager is by getting it from constructor.
class NeedsManager
{
protected $manager;
public function __construct(Manager $manager)
{
$this->manager = $manager;
}
}
You don't need to enforce one instance of Manager. Just don't instantiate it more than once. If all of your classes that need an instance of Manager get what they need from the constructor and never tries to instantiate it on their own, it will assure that there's just going to be one instance in your application.
How about option 3. If they are true singletons, set up properties files for their parameters for use with a no-arg getInstance.
If that doesn't fit, you might be misusing the singleton pattern.
You are looking at using a Factory design pattern. Factories are objects that act as fancy constructors for other objects. In your case, you will move setup and getInstance to the factory. The wiki article's pretty good- http://en.wikipedia.org/wiki/Factory_method_pattern
class SingletonFoo {
//properties, etc
static $singleton = NULL;
private function __constructor(){}
static function getInstance(){
if(NULL === self::$singleton) {
self::$singleton = new SingletonFoo();
}
return self::$singleton;
}
}
class FooFactory {
static $SingletonFoo = null;
static function setup($args){
if( !(NULL === self::$SingletonFoo)){
throw new AlreadyInstantiatedException();
}
self::$SingletonFoo = SingletonFoo::getInstance();
//Do stuff with $args to build SingletonFoo
return self::$SingletonFoo;
}
static function getInstance(){
if(NULL === self::$SingletonFoo) {
throw new NotInstantiatedException();
}
return self::$SingletonFoo;
}
}
Don't use Singleton, use Resources Manager (or Service Container, or DI Container):
class ResourceManager
{
protected static $resource;
public static function setResource($resource)
{
if (!empty(self::$resource)) //resource should not be overwritten
{
if ($resource!=self::$resource) return false;
else return true;
}
self::$resource = $resource;
return true;
}
public static function getResource()
{
return self::$resource;
}
}
Resource Manager allows you to set any custom classes for unit-testing (like dependency injection), you can just get needed resources without requesting them in constructor (I like DI, but sometimes it's just more handy to use empty constructors).
Ready-to-use variant: http://symfony.com/doc/current/book/service_container.html (I don't like to move logic from code to configs, but in stand-alone module it looks acceptable).
How will I use an instance of an object that is initially loaded throughout the whole site?
I want $myinstance to be used everywhere.
$myinstance = new TestClass();
Thanks!
What you are looking for is called the singleton pattern.
If you are deeply into OOP architecture, and want to do things like Unit Testing in the future: Singletons are regarded as an imperfect approach and not "pure" in the sense of OOP. I asked a question on the issue once, and got pretty good results with other, better patterns. A lot of good reading.
If you just want to get started with something, and need your DB class available everywhere, just use a Singleton.
You just need to declare your variable in global scope (for example, in the begginning of your whole code), and when you want to use it inside a function, use the "global" statement. See http://php.net/global.
I'm not 100% sure I got what you want to do... but I'll try to answer anyway.
I think you can save it to a session variable, using the serialize/unserialize functions to save/retrieve your class instance. Probably you'd code TestClass as a singleton, but that really depends on what you're trying to do.
For instance:
if (!isset($_SESSION["my_class_session_var"])) // The user is visiting for the 1st time
{
$test = new TestClass();
// Do whatever you need to initialise $test...
$_SESSION["my_class_session_var"] = serialize($test);
}
else // Session variable already set. Retrieve it
{
$test = unserialize($_SESSION['my_class_session_var']);
}
There is a design pattern called Singleton. In short:
Change __construct and __clone to private, so calling new TestClass() will end up with Error!
Now make a class that will create new instance of your object or return existing one...
Example:
abstract class Singleton
{
final private function __construct()
{
if(isset(static::$instance)) {
throw new Exception(get_called_class()." already exists.");
}
}
final private function __clone()
{
throw new Exception(get_called_class()." cannot be cloned.");
}
final public static function instance()
{
return isset(static::$instance) ? static::$instance : static::$instance = new static;
}
}
Then try to extend this class and define static $instance variable
class TestClass extends Singleton
{
static protected $instance;
// ...
}
Now try this:
echo get_class($myinstance = TestClass::instance();
echo get_class($mysecondinstance = TestClass::instance());
Done