Skip to content

Instantly share code, notes, and snippets.

@tatemz
Last active July 11, 2019 22:53
Show Gist options
  • Save tatemz/e3983f5cf4d8768b54a28c43c719fdb4 to your computer and use it in GitHub Desktop.
Save tatemz/e3983f5cf4d8768b54a28c43c719fdb4 to your computer and use it in GitHub Desktop.
Singleton factories for creating unique single and multi instance classes.
<?php
abstract class Multi_Singleton_Factory extends Singleton_Factory {
public static function get_singleton_key( $class, $args ) {
// Create a unique key based on instance-specific information (i.e. classname + args)
return md5( $class . '_' . serialize( $args ) );
}
}
<?php
abstract class Singleton_Factory {
public static $_instances = array();
public static function instance( $arg = '' ) {
// Get classname
$class = get_called_class();
// Grab the args in order to pass to the $class constructor
$args = func_get_args();
// Get the unique hash based on the classname and the passed args
$key = $class::get_singleton_key( $class, $args );
// If the $class instance does not exist...
if ( ! array_key_exists( $key, self::$_instances ) ) {
// If there are args to pass...
if ( count( $args ) > 0 ) {
// Create and store a new instance... also pass the args
$reflect = new ReflectionClass( $class );
// If the class has a constructor
if ( method_exists( $class, '__construct' ) ) {
// Create a new instance without invoking the constructor
$instance = $reflect->newInstanceWithoutConstructor();
// Get the constructor method
$constructor = $reflect->getConstructor();
// If the constructor is private, set it as public temporarily
if ( $protected = $constructor->isPrivate() )
$constructor->setAccessible( true );
// Call the constructor
$constructor->invokeArgs( $instance, $args );
// Return original constructor visibility
if ( $protected )
$constructor->setAccessible( false );
// If the class has no set constructor
} else {
$instance = $reflect->newInstanceArgs( $args );
}
// Store the instance
self::$_instances[ $key ] = $instance;
// Otherwise create and store a new instance normally.
} else {
self::$_instances[ $key ] = new $class;
}
}
// Return the stored singleton instance
return self::$_instances[ $key ];
}
public static function get_singleton_key( $class, $args ) {
// Only return the classname. This behavior can be modified in child classes
return $class;
}
private function __construct() {}
}
<?php
class App extends Singleton_Factory {
private function __construct() {
echo 'This can only output one time.';
}
}
App::getInstance();
App::getInstance();
<?php
class Person extends Multi_Singleton_Factory {
private function __construct( $first_name, $last_name ) {
$this->first_name = $first_name;
$this->last_name = $last_name;
}
}
$john = Person::getInstance( 'John', 'Doe' );
$jane = Person::getInstance( 'Jane', 'Doe' );
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment