Registry or Singleton pattern in PHP? - php

I am working with PHP classes and objects now. In this question the names of fields and methods are made up just so you get an idea of what I am talking about.
It is related to using the singleton and registry design patterns.
Now lets say I need to access a Database object, Cache Object, Core Settings object, Session object in almost every other class I will need to have access to these. SO I would use a registry to store all 4 of those object into 1 registry class object. I could then easiyl just pass in my 1 object into any other object that needs to access these. So that sounds great so far but what if I have some classes that do not need all 4 of those objects, what If I ONLY need to access the Database object or the Session object in some of my other classes? For perfromance would it be best to just use a singleton inside these other objects or would it be the same to go ahead and use my registry in these?
I do not know well enough how the objects work in PHP to know if there would be any sort of performnce gain (less memory usage, cpu usage, load time).
So anyone with experience in this maybe can tell me if there would be any gain using one or the other, I am at the stage where I can go ether way without it affecting production time or anything. I would like to use the best method if I can now.

That depends on your application. If you still need 3 out of the 4 classes, then it'd be more ideal to use the Registry than to handle the 3 independently only because you don't need the fourth. Loading the classes lazily would be one approach to reduce memory footprint, but then you need to instruct the registry when to create the objects and that's not much different than handling singletons. Alternatively, you could create an n-parameter constructor or use an array to instruct your Registry which classes to instantiate during construction.
class Registry {
public $class1;
public $class2;
function __construct($uses) {
foreach($uses as $class) {
$this->{$class} = new {$class}();
}
}
}
Then instantiate your Registry by specifying which classes to instantiate.
$reg = new Registry(array('class1'));
You would obviously want your constructor to handle zero parameters to account for instantiating all classes by default.

You can implement lazy loading to only load the objects you really need:
class Registry
{
private static $database = null;
private static function connectDatabase($key)
{
[... do connection stuff ...]
}
public static function getDatabase($key)
{
if (Registry::$database == null)
{
Registry::connectDatabase($key);
}
return Registry::$database;
}
}
The code to register the database connection parameters is left as exercise to the reader.

Perhaps this is the proper Singleton-Registry pattern. OFC, you can implement different things, SplFixedArray, ArrayAccess interface, and others. Also it is not bad to add the destruct and destroy inner objects to ensure no leak possible.
class oRegistry{
private static $instance = null;
private $storage = array();
private function __construct(){}
private function __clone(){}
public static function getInstance(){
if( self::$instance === null ){
self::$instance = new self();
}
return self::$instance;
}
public function attach($name, $o) {
if( true === isset($this->storage[$name]) ) {
throw new Exception('The instance with name '.$name.' already exists in registry.');
}
if( !empty( $name ) ) {
$this->storage[ $name ] = $o;
}
}
public function detach( $name ){
if( isset( $this->storage[ $name ] ) ) {
$this->storage[ $name ] = null;
unset( $this->storage[ $name ] );
}
}
public function get( $name ){
if( false === isset( $this->storage[$name] ) ) {
throw new Exception('Invalid instance requested');
}
return $this->storage[ $name ];
}
}
// usage example
$storage = oRegistry::getInstance();
$obj = new stdClass;
$obj2 = new stdClass;
$obj->test1 = 'test';
$obj2->test2 = 't2';
$storage->attach( 'test1', $obj );
$storage->attach( 'test2', $obj2 );
$got = $storage->get( 'test2' );
var_dump($got); // object(stdClass)#3 (1) { ["test2"]=> string(2) "t2" }
$storage->detach( 'test2' );
$got = $storage->get( 'test2' );
var_dump($got); // bool(false)

Related

Initialize php object with arguments, while its constructor doesn't take any (singleton pattern)

I have only basic PHP knowledge and am reading the book "PHP 5 E-commerce Development.pdf" which code source can be found here: https://github.com/rogeriorps/books_demo.
I am right at the beginning, on the creation of the registry with "objects" such as database handling, authentication and template sending.
I have a problem with the last line of code of this function, in a class that is a singleton and has objects:
public function storeObject( $object, $key )
{
if( strpos( $object, 'database' ) !== false ) {
$object = str_replace( '.database', 'database', $object);
require_once('databaseobjects/' . $object
. '.database.class.php');
} else {
require_once('objects/' . $object . '.class.php');
}
self::$objects[ $key ] = new $object( self::$instance );
}
Well, for the authentication class for instance, the constructor is empty: public
function __construct() { }
So it would require authentication.class.php and then create a new authentification(self::$instance)... On a constructor has no arguments!
How is that possible? What bothers me is the use of the word new, which normally calls the empty constructor, and gives it arguments out of the blue.
Any further explanations about how this all works are welcome as well, thank you :-)
PHP is a quite forgiving language, in that certain language constructs and practices are not as strictly applied as in other programming languages.
PHP does not complain if you provide more parameters than a class method expects, whether that method is a costructor or regular method. See below, which outputs "Hello World!" just fine:
error_reporting(E_ALL);
ini_set('display_errors', TRUE);
ini_set('display_startup_errors', TRUE);
class Foo
{
public function __construct() {}
public function hello($input) { return 'Hello ' . $input . '!'; }
}
$foo = new Foo(123);
echo $foo->hello('World', 'Universe');
I'm still trying to understand what your question is.
While the link to the source code is good, can you be more specific as to what files you are talking about.
Is this the line you are referring too? :
//I will call this class 'Singleton',as I have no idea what it's name is.
class Singleton
{
protected static $instance;
protected static $objects = [];
...
public function storeObject( $object, $key )
{
...
self::$objects[ $key ] = new $object( self::$instance ); //<--- this line
...
}
}
And then you say you have a class like this ( with an empty constructor )
class authenticate{
public function __construct() {} //empty
}
IF I follow that right, the extra argument is ignored in this case. However, consider having another class that can be stored in Singleton
class user{
//instance of singleton
protected $singleton;
public function __construct( $Singleton ) {
$this->singleton = $Singleton;
}
}
So in this case the same class Singlton calls a different class that does accept an instance of Singlton.
This is what I would call a form of Polymorphism.
Polymorphism is the provision of a single interface to entities of different types.
Personally I would prefer they actually have an interface for this. I will try to explain this as best I can. An interface can be thought of like a contract, it guarantees that any class implementing it will expose some public methods, with given arguments, in a specific order.
For example this
interface StorableObjectInterface{
//interfaces do not contain a method body, only the definition
//here I am using type hinting to tell it to only accept instance of Singleton
public function __construct( Singleton $Singleton );
}
So what this does is require that every class that implements this interface requires an instance of singleton as it's constructors first argument. They can still ignore it, but it should be a contractual obligation of being called from Singleton (IMO).
Then your clasess would look like this
class authenticate implements StorableObjectInterface{
public function __construct(Singleton $Singleton) {} // still empty
}
class user implements StorableObjectInterface{
//instance of singlton
protected $singlton;
public function __construct(Singleton $Singleton ) {
$this->singlton = $Singleton;
}
}
And then to lock it all together in Singleton you would check that $Object implements the interface.
public function storeObject( $object, $key )
{
...
if( is_a( $object, StorableObjectInterface::class ){
self::$objects[ $key ] = new $object( self::$instance );
}else{
//throw exception
throw new Exception("Class {$object} must implement interface ".StorableObjectInterface::class);
}
...
}
This is the way I would do it... It wasn't clear if you are just Using someones system, or creating your own.
So you may wonder why go through all this trouble, I'll give you an example.
Say later on you may need something like a path to a config file in authenticate, so you can easily load you credentials etc.
So you look in that class and see this ( we'll forget we know what we know )
class authenticate{
public function __construct() {} // still empty
}
So you figure you can just tack it in the constructor ( say you were using this class somewhere outside of Singlton ). So you change it.
class authenticate{
protected $config;
public function __construct($configFile = null) {
if( $configFile )
$this->config = include $configFile;
}
}
//then you call it for you new code
$z = new authenticate('passwordsAndStuf.php');
This is all fine until Singleton calls that constructor with an instance of itself. Now everything blows up. The main issue is that just looking at authenticate there is no way to tell this is going to happen. So by adding an Interface we are making a contract with Singleton any class implementing this interface will always accept an instance ofSingleton` as the first argument.
Hope that makes sense.

how to use more model in MVC

As i know in MVC, Model always connect to database, example:
class a extends Model {
...
}
class Model {
public function __construct() {
$db = new database;
$db->connect('localhost','root','','example');
}
}
But, in the case i have more Model always run to get config in database. So, when run website will be 2 Model are used.
This equivalent to 2 connect to database so its has effect to system when have many people visit my website (200 request = 400 connect to database)
About model
Actually model is not at class in the first place. Model is a layer, which contains multitude of objects. The two main groups of class instances in model layer are tasked with one of following responsibilities:
domain business logic and rules: implemented by domain objects (1) (2)
data access and persistence: usually implemented as datamappers (3)
In code it would looks something similar to this:
$user = $factory->buildObject('user');
$mapper = $factory->buildMapper('user');
$user->setId( 42 );
$mapper->fetch($user);
$now = time();
if ( $user->hasStatus( User::STATUS_LOCKED ) && !$user->isBanned( $now ) )
{
$user->setStatus( User::STATUS_AVAILABLE );
}
$mapper->commit($user);
As you might notice, at no point the business object actually interacts with database. Or is even aware of it. It might be that the information is stored in a plain text file, or via remote REST API, or in some noSQL thing. Domain object does not care about that. All the storage is handled by the mapper. The business logic that governs the making of invoice does not depend on location where the information about invoice comes from.
About connections
Since you are using OOP, you might take advantage of it. Consider this example:
class Test
{
protected $ob = null;
public function __construct( $ob )
{
$this->ob = $ob;
}
public function get()
{
var_dump( $this->ob->data );
}
public function set( $val )
{
$this->ob->data = $val;
}
}
$object = new stdClass;
$foo = new Test($object);
$bar = new Test($object);
$foo->set('lorem ipsum');
$bar->get();
To see executed: http://codepad.org/coCibwyk
You should notice, that both instances of Test class are sharing the same instance. In your code, you can do the same with instance of PDO.
And if you are using something similar to first code snipped , then :
class Factory
{
protected $connection = null;
public function __construct( $connection )
{
$this->connection = $connection;
}
public function buildMapper( $className )
{
$className = $className . 'Mapper';
$instance = new $className ;
$instance->useConnection( $this->connection );
return $instance;
}
// ... some other code
}
So, when you use $mapper = $factory->buildMapper('user'); , the method creates an object, which already has a connection.

constructor versus too freaking many gets and sets

I have a record class with 18 properties.
Before that class can be submitted to the database, all 18 properties must have validated data.
Because I'm OOP-ifying a working procedural webapp, I went about this sort of backwards.
First I addressed workflow for modifying existing records. At the time, it made sense to throw all 18 properties into the __construct method and avoid craploads of setters. A separate loader class handles the dbase business and can return either single objects or an array of record objects. That all worked ok.
But then it came time to address the new record creation workflow, and suddenly I needed to instantiate an empty record, except my record constructor is a hungry beast that wants 18 parameters...
...so you strip the constructor? But then I'd have to add 18 setters and call them all each time I want to work with an existing record...
doesn't seem like much of an improvement! :-/
How do real programmers handle this? (I'm just a weenie hobbyist...)
Either default arguments is one option, but then you have to fill out a large number of null's if you only want to use, say, the first and last.
Then again, you could do array looping:
private $prop1;
private $prop2;
// more properties here.
function __construct( array $props ) // `array` here is for type-hinting.
{
foreach( array( 'prop1', 'prop2' /*, all of the props for this object */
as $property )
{
// basically, this will assign all of the properties as they exist in the
// props array
if( isset( $props[ $property ] ) )
$this->$property = $props[ $property ];
}
}
Or, if you wanted to keep your old constructor signature:
function __construct( $prop1, $prop2 = NULL, $prop3 = NULL /* ... */ )
{
if( is_array( $prop1 ) )
{
$this->array_prop_assignment( $prop1 );
}
else
{
$args = func_get_args();
// this ensures that anything which is passed to the constructor
// will go to the "new" old constructor
call_user_func_array( array( $this, 'param_prop_assignment' ), $args );
}
}
function param_prop_assignment( $prop1, $prop2 /* ... */ )
{
//your old constructor can go here.
}
function array_prop_assignment( array $props )
{
// foreach example above would go here.
}
The new version also gives you the option to simply:
$k = new DataClass(); // no idea what the real class name is.
$k->param_prop_assignment( 1, 2, 3 /* ... */ );
Stuffing 18 parameters in any sort of function is (constructor included) is bad. You'll never remember the correct order when you look at your code few months, or even few days from now on. Further more, as you experienced, when you need to extend the class it's hard.
That's why I usually prefer having classes with getters and setters. Yes it's more typing, but with getter and setters users can easily see what properties they can get and set, plus getter and setters are IDE's auto-complete friendly.
Now, the next problem is you don't want to call setters all the time when you read existing record from the database? You said you have a Loader class, can't you just centralize all the calls to setters in the Loder class?
class Loader{
public function getMyObject(){
$dbData = $this->getDataFromDB();
$myObj = $this->createMyObjectFromDbData($dbData);
return $myObj;
}
private createMyObjectFromDbData($dbData){
$myObj = new MyObject();
/* 18 setter calls */
return $myObj;
}
}
So when you want to work with existing you can simply call Loader.getMyObject();
If you don't feel like typing out all the 18 setter calls in createMyObjectFromDbData, then as long as your setter follows some naming convention you can do
for ($dbData as $columnName => $columnValue){
$propertyName = $columnName;
$propertyValue = $columnValue;
$myObj->set{$columnName}($propertyValue); /* you can't do this in java */
}
You may also want to add a validate method to validate all the properties in the object so you can call that method before you submit it to be inserted into database.
You can chain them to the constructor. Where you do this ...
$Record = Record()->Name('Mark')->Location('A-Town, NY')->Phone('123-345-6789');
You can do this by making a function that has the same name as your class that returns a new instances of your class.
function Record() {
return new Record;
}
class Record {
private $Name;
private $Location;
private $Phone;
public function __get($property) {
return (isset($this->$property)) ? $this->$property : FALSE;
}
public function &__call($property, $arguments)
{
if (property_exists($this, $property))
$this->$property = array_shift($arguments);
return $this;
}
}
$FilledRecord = Record()->Name('Mark')->Location('A-Town')->Phone('123-456-7890');
$EmptyRecord = Record();
print_r($FilledRecord);
print_r($EmptyRecord);
If you need to validate some data, you can just add the function on later.
In a perfect world your object would allow you to specify values using either the constructor or setters. What you could do to simplify things is provide a constructor that only accepts a subset of the 18 values and sets the rest to default values. But that assumes that there are default values that make sense, which may not be the case.
If you have a lot of properties for an object and you don't want to include them all in the constructor, you can use setters return the object itself to make slightly more readable code:
MyClass obj = (new MyClass())
.setName(name)
.setLocation(location)
...
.setPhone(phone)
Along the same lines, if all of the values need to be validated before you have a valid object, you can use a builder object to do the same thing. Basically, you create a builder object, set the values, and then tell the builder to create the actual object. It can then do the validation of all the values (including validation that uses multiple fields) right before it constructs the actual instance of the object.
MyClass obj = (new MyClassFactory())
.setName(name)
.setLocation(location)
...
.setPhone(phone)
.construct();

Using log4php in a static context

I'm currently in the process of moving from our own proprietary logging solution to log4php.
We use a lot of classes with only static methods in our project. The documentation defines the basic use case like:
class MyClass {
private $logger;
public function __construct() {
$this->logger = Logger::getLogger(__CLASS__);
$this->logger->debug('currently in constructor');
}
}
But I can't use that, cause I need $logger to be available in a static context as well. Making $logger static as well doesn't help either, because the constructor for my class is never called (as all its members are static).
The documentation tells me to use a static initializer for that member then. But then I would have to remember to call that for all classes I use. And that seems too error-prone.
So I came up with this:
class Foo {
private static $logger = null;
private static function logger() {
if( null == self::$logger ) self::$logger = Logger::getLogger( __CLASS__ );
return self::$logger;
}
public static function bar() {
self::logger()->debug( "test" );
}
}
Foo::bar();
But that seems like too much overhead as well. So, any suggestions?
I came up with one solution that works quite well but requires $logger to be public.
class Foo {
public static $logger = null;
public static function bar() {
self::$logger->debug( "test" );
}
}
$loggerName = "logger";
// Iterate over all declared classes
$classes = get_declared_classes();
foreach( $classes as $class ) {
$reflection = new ReflectionClass( $class );
// If the class is internally defined by PHP or has no property called "logger", skip it.
if( $reflection->isInternal() || !$reflection->hasProperty( $loggerName ) ) continue;
// Get information regarding the "logger" property of this class.
$property = new ReflectionProperty( $class, $loggerName );
// If the "logger" property is not static or not public, then it is not the one we are interested in. Skip this class.
if( !$property->isStatic() || !$property->isPublic() ) continue;
// Initialize the logger for this class.
$reflection->setStaticPropertyValue( $loggerName, Logger::getLogger( $class ) );
}
This I only have to define the $logger property once per class and run my initialization code once (I guess after the require_once section of the entry point of my application).
The performance impact of that code is negligible, especially since it is only run once (compared to my initial solution). This is what I measured inside a VirtualBox VM on an Intel Core2 Q9450 #2.66GHz:
10000 iterations for 157 classes completed in 2.6794s. Average per iteration: 0.00026794s

Creating a good registry class in PHP for important classes

I have a webapplication where I use a registry class. The registry class holds important classes that I need troughout my application.
I have made the registry class a Singleton class and this class is static.
The content of the registry class is here:
<?php
class registry
{
private static $objects = array();
private static $instance;
private function __construct(){}
private function __clone(){}
public static function singleton()
{
if( !isset( self::$instance ) )
{
self::$instance = new registry();
}
return self::$instance;
}
public function storeObjects()
{
$Objects = array_merge($GLOBALS['EXTRA_LIBS'],array('data','page','session','uri','loader','modules'));
foreach($Objects as $name)
{
$this->$name = $name;
}
}
public function __set( $object, $key )
{
require_once(__LIBRARIES . DS . $object . '.class.php');
self::$objects[ $key ] = new $object( self::$instance );
}
public function __get( $key )
{
if( is_object ( self::$objects[ $key ] ) )
{
return self::$objects[ $key ];
}
}
public function returnAllObjects()
{
return self::$objects;
}
}
?>
Now whenever I want to use one of the classes here in my application I do:
registry::singleton()->data->adddata('somedata');
I use the classes a lot in my application, minimum of 1 time in every method.
Now my question is what is the best thing to do:
1) call the whole thing everytime
2) Class $registry = registry::singleton(); one time in every method and then just use the local variable. (I do not know if this will work)
Or is there a more elegant method to tackle this problem.
Whether you assign the registry instance to a local variable or not is irrelevant. If this is your only concern, use what makes the code more readable in the specific block of code.
I'd be more concerned about the implications of having to hardcode the Registry classname into my other classes and whether I really need a Singleton for the Registry. Have a look at Dependency Injection.
(2) would work just fine, try it. If you're using it a few times in each method it will save you some typing.
You could consider adding some sanity checking in __set() to make sure the file exists before require_once, as well as logging and/or returning an error if it doesn't (same for __get()).

Categories