what I'm trying to achieve (PHP 5.3) is to have an accessor to my representation of, for example, the HTML Body of a page. Instead of echoing everything directly it should be added to an array of entries in that singleton. Example: myBodyClass::add('<h1>Title</h1>');
add() is declared as public static function add($strEntry) {}
Now should I just add them to a static array $entries like self::$entries[] = $strEntry; (class VersionB) or should I use an instance like self::getInstance()->entries[] = $strEntry;? (class VersionA) (whereby getInstance() would of course instanciate ´...new self;´ if necessary)
I don't quite understand the difference yet, I'm afraid.
The second part of my question is how to print the object. The PHP manual is a bit thin about why __toString() cannot be static - but then again I would understand a parser to have a problem distinguishing echo myBodyClass from a constant (so is that the reason?)
Ideally I would like to call add() as often as needed to add all parts of the body, and then use something like echo myHeaderClass, myBodyClass, myFooterClass; at the end of the script, which should invoke the __toString() methods within the classes.
Thanks for pointing me into the correct direction.
Code Example
class VersionA
{
private static $instance = null;
private $entries = array();
private final function __construct(){}
private final function __clone(){}
private static final function getInstance()
{
if (self::$instance === null) :
self::$instance = new self;
endif;
return self::$instance;
}
public static function add($sString)
{
self::getInstance()->entries[] = $sString;
}
public static function getHtml()
{
return implode("\r\n", self::getInstance()->entries);
}
}
class VersionB
{
private static $entries = array();
private final function __construct(){}
private final function __clone(){}
public static function add($sString)
{
self::$entries[] = $sString;
}
public static function getHtml()
{
return implode("\r\n", self::$entries);
}
}
(Copied from comments, as requested by OP...)
You're missing the point of a singleton. There is a difference between a singleton object and a static class. If you want to use methods that act on an object (like __toString()), then you need it to be an object; a static class isn't good enough. If you want to avoid calling getInstance all the time, then set a variable to the object, and pass it around everywhere like you would with other objects, per the Dependency Injection pattern. That would probably be best practice advice anyway.
The thing with a static class is that it isn't really OOP; it's just a bunch of global functions with a shared class name. One may as well use plain functions with a namespace declaration.
But the main reason for using a genuine singleton is swappability. Assuming you follow my advice above and create a single reference to the object that you pass around your code, it becomes a lot easier to swap in an alternative object since you don't have the hard-coded class name being referenced all over the place. This makes it a lot easier to write decent unit tests for your code that uses the class.
Hope that helps.
You should probably not use a static add method.
The idea of a singleton is that you create a single instance of a class so that external objects can interact with that instance. That means that your add method should not be static.
You could do something like:
class MyBodyClass
{
protected $entries = array();
protected $instance;
public static function getInstance()
{
if (is_null($this->instance)) {
$this->instance = new self();
}
return $this->instance;
}
private function __construct() {}
public function add($strEntry)
{
$this->entires[] = $strEntry;
}
}
And call it like this:
MyBodyClass::getInstance()->add('<h1>blah</h1>');
Something like this should work:
class MySingleton
{
public static function getInstance()
{
static $inst = null;
if ($inst === null) {
$inst = new MySingleton();
}
return $inst;
}
private function __construct() { }
public static function add() {}
public function __toString() {
echo 'Something';
}
}
$body = MySingleton::getInstance();
$body::add('Something');
echo $body;
Related
I've been looking if there exists something like a static initializer in PHP.
Here is a static method as a Java example:
public class Foo {
static { //This is what I mean (Does this exist in other languages like PHP?
//THIS IN PHP
}
}
I found what it's name (static initializer). It is used the first time the Class its loaded. Seems like theres not static initializer in PHP.
I don't think PHP provides any direct ways to initialize classes like it's done in Java or C#. If you want to initialize static class members you can do it within a constructor, something like this:
class MyClass {
private static $staticValue;
public function __construct() {
if (self::$staticValue === null){
self::$staticValue = 'Nice';
}
}
}
However, the above approach won't work if you never instantiate your class. That means that accessing static class members won't trigger the code in __construct unfortunately, and I don't think there's any workaround for this problem in PHP.
Static properties and methods in PHP
class SomeClass {
private static $property = 'Foo';
public static function getProperty() {
return self::$property;
}
}
SomeClass::getProperty();
Non static properties and methods
class SomeClass {
private $property = 'Foo';
public function getProperty() {
return $this->property;
}
}
$class = new SomeClass();
$class->getProperty();
I wrote the following example class:
class Test {
public $baseSymbol;
public $counterSymbol;
public function __construct($baseSymbol,$counterSymbol) {
$this->baseSymbol = $baseSymbol;
$this->counterSymbol = $counterSymbol;
}
public static $var = new Test("CV", "SWR");
}
As you may noticed, I want that the attribute $var of the class Test become a Object of type Test. I did the same thing easily in Java, as a public static variable, but in PHP it's not working...Is there any alternative for what I'm trying to do?
Because you cant set complex types within the definition of the class variables, the only way I can perceive doing this in PHP is to use the magic of procedural code ( Joke ). Now It's important to note that within the file the class exists in you can certainly do something like this.
class Test {
public $baseSymbol;
public $counterSymbol;
protected static $var;
public function __construct($baseSymbol,$counterSymbol) {
$this->baseSymbol = $baseSymbol;
$this->counterSymbol = $counterSymbol;
}
public static setVar(Test $var ){
self::$var = $var;
}
}
Test::setVar( new Test() );
This is pretty standard fare, but as mentioned above by placing the setting code within the class, when the file is loaded the setting is done immediately and pre-loads the class instance before anything else can be done.
This is simply a consequence of not being pre-compiled. When the class is loaded there is no guarantee that a complex object that is required is present, and because of that PHP plays it safe and restricts this ability.
I did change the variable to be protected to keep it encapsulated, this of course is optional. I also added type casting which will insure that only an object or descendant object of Test is used as the input.
Probably not the most favorable solution but one that will work. One last thing you could do just to make sure if you really want to keep it from being changed is to change the setter like this.
public static setVar(){
if( !self::$var ){
self::$var = new Test();
}
}
This way you just call the method with Test::setVar() and once it's got a value it always returns not false, so it will not be changed latter.
One last note, if you truly want a copy of the class itself, this is the Test class with a static instance of itself ( like a singleton ) then do this instead of using the name
public static setVar(){
if( !self::$var ){
self::$var = new self;
}
}
Now to wrap that into a singleton, you can do the class like this.
final class Test {
public $baseSymbol;
public $counterSymbol;
protected static $var;
//no constuction
private function __construct($baseSymbol,$counterSymbol) {
$this->baseSymbol = $baseSymbol;
$this->counterSymbol = $counterSymbol;
}
//no cloning
private function __clone(){}
public static getInstance(){
if( !self::$var ){
self::$var = new self('%', '#');
}
return self::$var
}
}
$Test = Test::getInstance();
Here I go rambling, now ponder saving the instance in an array with a key. Then you can have a Multiton ( is that a thing? );
public static getInstance($type, $baseSymbol,$counterSymbol){
if( !isset(self::$var[$type] )){
self::$var[$type] = new self($baseSymbol, $counterSymbol);
}
return self::$var[$type];
}
It makes a great database class, just saying.
You could access $var via a getter and initialize it there on demand:
private static $var;
public static function getVar()
{
if (null === self::$var) {
self::$var = new Whatever();
}
return self::$var;
}
I'd like to have a library class that maintains state across the same request. My use case is that I want to pass 'messages' to the class, and then call them at any time from a view. Messages can be added from any part of the application.
I had originally done this via static methods, which worked fine. However, as part of the lib, I also need to call __construct and __destruct(), which can't be done on a static class.
Here's a very simple example of what I am trying to do:
class Messages
{
private static $messages = array();
public function __construct()
{
// do something
}
public function __destruct()
{
// do something else
}
public static function add($message)
{
self::$messages[] = $message;
}
public static function get()
{
return self::$messages;
}
}
I can then add messages anywhere in my code by doing
Messages::add('a new message');
I'd like to avoid using static if at all possible (testability). I have looked at DI, but it doesn't seem appropriate, unless I'm missing something.
I could create a class (non-static) instead, but how do I then ensure that all messages are written to the same object - so that I can retrieve them all later?
What's the best way to tackle this?
I looks like you could benefit from using the Singleton pattern - it is designed for an object that must have only one instance throughout a request. Basically, you create a private constructor and a static method to retrieve the sole instance. Here is an example of a singleton that will do what you describe.
<?php
class Messages
{
private static $_instance;
private $_messages = array();
private function __construct() {
// Initialize
}
static public function instance() {
if (! self::$_instance) {
self::$_instance = new self();
}
return self::$_instance;
}
public function add_message( $msg ) {
$this->_messages[] = $message;
}
public function get_messages() {
return $this->_messages;
}
private function __destruct() {
// Tear-down
}
}
$my_messages = Messages::instance();
$my_messages->add_message( 'How now, brown cow?' );
// ...
$your_messages = Messages::instance();
$msgs = $your_messages->get_messages();
echo $your_messages[0]; // Prints, "How now, brown cow?"
Since the constructor is private, you can only create a Messages object from within a method of the object itself. Since you have a static method, instance(), you can create a new Messages instance from there. However, if an instance already exists, you want to return that instance.
Basically, a singleton is the gatekeeper to its own instance, and it stubbornly refuses to ever let more than one instance of itself exist.
Sounds like you are wanting to do a Singleton class. This will create an instance in one class and allow you to access that same instance in another class. Check out http://www.developertutorials.com/tutorials/php/php-singleton-design-pattern-050729-1050/ for more information.
How about making it a singleton class?
class Messages
{
// singleton instance of Messages
private static $instance;
public function __construct() { ... }
public static function getInstance()
{
if (!self::$instance)
{
self::$instance = new Messages();
}
return self::$instance;
}
}
This would ensure that all your messages get written to the same object, and also allow you to call __construct and __destruct
What you need is the Singleton pattern:
final class Singleton {
// static variable to store the instance
private static $instance = NULL;
// disable normal class constructing
private function __construct() {}
// instead of using the normal way to construct the class you'll use this method
public static function getInstance() {
if (NULL === self::$instance) {
self::$instance = new self;
}
return self::$instance;
}
// disable external cloning of the object
private function __clone() {}
}
// get the instance across some of your scripts
$singleton = Singleton::getInstance();
Sounds a bit like you want a singleton, although as an anti-pattern I'd avoid it.
You could do a full static class where every static member calls a self::_isBuilt(); method to do your construct elements. Destruct is a little trickier.
The best case for your needs might be a normal (non-static) class that you build right away and then access from a global... not super neat, but allows construct/destruct and members, and your statics to use $this which could be helpful. If you don't like the global variable, you could also wrap it in a method (a trick used in JS a fair bit) but it's not really any neater.
As a normal global class:
$myClass=new myClass();
//Access anywhere as:
globals['myClass']->myFunction(..);
Wrapped in a function
function my_class() {
static $var=null;
if ($var===null) $var=new myClass();
return $var;
}
//Access anywhere as:
my_class()->myFunction(..);
I've coded a simple configuration class for my own framework.
There are simple functions like get(), set() or loadFile().
But all functions and variables are static.
And now I want to implement an autosave mechanism. I had the idea to create an instance (in my init() function) whose __destruct() will call the static destruct() function:
<?php
class Config
{
static private $autoSave;
static public function get() {} /* set(), save(), load(), etc. */
static public function init($autoSave)
{
self::$autoSave = $autoSave;
new Config();
}
static public function destruct()
{
if (self::$autoSave)
self::save();
}
public function __destruct()
{
Config::destruct();
}
}
?>
Are there any better solutions or is my design pattern completely wrong in this case?
Are there any better solutions or is my design pattern completely wrong in this case?
Destructors are called on objects only, not for static classes.
Instead you could convert your class from static to regular so you can create an instance of it. Then it will have the destructor. Additionally it makes your code easier to re-use and test.
Additionally you're able to implement magic methods for __get and __set or ArrayAccess which often is useful for easy data storage and access as for a configuration.
Alternatively, you can add a destructor object to a static class member to achieve what you're looking for:
class ConfigDestructor
{
public function __destruct()
{
Config::destruct();
}
}
class Config
{
static private $destructorInstance;
static private $autoSave;
static public function get() {} /* set(), save(), load(), etc. */
static public function init($autoSave)
{
if (null === self::$destructorInstance)
self::$destructorInstance = new ConfigDestructor();
self::$autoSave = $autoSave;
}
static public function destruct()
{
if (self::$autoSave)
self::save();
}
}
Just FYI: You wrote you want to add an auto-save functionality. There is a common gap to fall over for both __destruct() and register_shutdown_function:
Note: Working directory of the script can change inside the shutdown function under some web servers, e.g. Apache.
You should specify an absolute path to access the file you want to save into. See as well: PHP file creation/write within destructor.
Inside your init method, add a call to register_shutdown_function:
register_shutdown_function(array('Config', 'destruct'));
Have you looked at register_shutdown_function? You could add your method to the shutdown part of the script.
It could also be worth it to look at the Singleton pattern.
You can create an instance of this static class on autoregister.
$instance = array();
spl_autoload_register(function ($class)
{
...
global $instance;
if ($isStatic) $instance[] = new $class();
...
});
This is working fine for me.
... and for those who don't like readable code (it is untested):
class staticInstances()
{
private static $list = array();
public static function add($class)
{
self::$list[] = new $class();
}
function __distruct()
{
foreach (self::$list as $class)
unset(self::$list);
}
}
$staticInstances = new staticInstances();
spl_autoload_register(function ($class)
{
...
if ($isStatic) staticInstances::add($class);
...
});
I am going to use singleton classes to manage both DB connections and references to application settings.
It seems a little messy to have to use the following code in every method in order to access the db class.
$db = DB::getInstance();
Is there a more efficient way of going about it?
Any advice appreciated.
Thanks
I often use the Registry pattern, where this behavior occurs as well. I always set a instance variable in the constructor of my models to point to the Registry entry;
class Registry {
private static $_instance;
private $_registry;
private function __construct() {
$_registry = array();
}
public static function getInstance() {
if (!Registry::$_instance) {
Registry::$_instance = new Registry();
}
return Registry::$_instance;
}
public function add($key, &$entry) {
$this->_registry[$key] = &$entry;
}
public function &get($key) {
return $this->_registry[$key];
}
public function has($key) {
return ($this->get($key) !== null);
}
}
Model example;
class MyModel {
private $_db;
public function __construct() {
$this->_db = Registry::getInstance()->get('dbKey');
}
/* Every function has now access to the DAL */
}
Instantiation example;
$dal = new Db(...);
Registry::getInstance()->add('dbKey', $dal);
...
$model = new MyModel();
$model->doDbStuff();
Another approach is to always pass the reference as a parameter to each constructor.
Of course I only use this behavior when most of the methods in my model use the reference, if only a few (one or two) methods have use of the reference, I call the Registry/Singleton like you showed.
It is not messy. This is an intended behavior of Singletons. And, actually, this is just one line of code. Do you wish to make it even more compact? :)
My preferred method is to create a Base class which all the classes that need db access descend from. Base calls the singleton(s) in its constructor. All its children call their parent constructor. e.g.:
class Base {
protected $db;
public function __construct(){
$this->db = DB::getInstance();
}
}
class Achild extends Base {
protected $var1;
public function __construct($arg){
parent::__construct();
$this->var1=$arg;
}
}
I know what you mean... hate that ::getInstance() stuff! So go and use static methods:
class DB {
private static $db;
public static function getInstance() {
if(!self::$db) {
self::$db = new DBconnector();
}
}
public static function query($query) {
return self::$db->query($query);
}
}
Usage is much nicer:
$result = DB::query('SELECT whatever;');
And if you use PHP 5.3 you can write a __callStatic similar to this, to forward all the method calls to the object:
public static function __callStatic($method, $args) {
call_user_func_array(array(self::$db, $method), $args);
}
And to make me happy, add an __autoloader so that you can access DB without any worries any time!