Static initializer or static constructor in PHP? - php

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();

Related

PHP: is it possible to call a static class method from another static class?

Consider a static class (private constructor, only static methods & variables).
Now the rough class definition would look like this:
class A{
private function __construct(){}
public static test(){};
}
class B{
private function __construct(){}
}
Is it somehow possible to call something like B::A::test() ?
Or maybe through a variable? Something like B::$A::test() ?
I guess it is possible by some general call catching, but I can't figure it out...
IMPORTANT: Also, I want to call ANY other static class from B, not just from the A class...
EDIT2: What I want to achieve is to call static class through another static class, if possible... very similar to calling a method from object variable - but static class (obviously) is not ment to be instantiated.
EDIT3: Also possible solution is to call it as B::CLASSNAME_METHOD_NAME and catch it by __callStatic but I would rather do B::CLASSNAME::METHOD_NAME ...
Another possible solution:
If you don't want to create whole singleton, this could be solution - creating a partial singleton - some kind of singleton-hepler, altough using -> to call a static method could be confusing!
class AA{
private function __construct(){}
private static $instance;
public function getInstance(){ return empty(self::$instance)?(new self()):self::$instance; }
public function __call($method_name, $args) {
return AA::$method_name($args);
}
public static function test($a, $b){
echo "TEST: A:".$a." B:".$b;
}
}
class B{
private function __construct(){}
public static function A(){
return AA::getInstance();
}
}
B::A()->test("one", "two");
You would have to use this syntax:
class B {
const A = 'A';
}
$class = B::A;
$class::test()
This is essentially just the syntax for calling a static method on a variable class name. There's no nicer shortcut for it.
Note that I don't think such a pattern makes a lot of sense, your class design is too static at this point. You should be instantiating your classes and call $b->a->test(), which gives you more flexibility in your application design. Realistically B::A is hardcoded, it's not going to be anything other than 'A', so you may as well write A::test() directly.
If instead of a const you'd use a public static property which may vary at runtime, you now introduce global state into your app, which is also undesirable.
calling static function of a class from a static function of an another class
class A{
private function __construct(){}
public static function test()
{
echo 'from class A';
}
}
class B{
private function __construct(){}
public static function test()
{
return A::test();
}
}
A::test(); //outputs 'from class A'
B::test(); //outputs 'from class A'

Abstract trait't method not allowed to be static in PHP?

Here is my example:
trait FileConfig {
public static function getPathForUploads() {
$paths = static::getPaths();
//etc.
}
abstract public static function getPaths(); //doesn't work. Error: "Static function SharedDefaultConfig::getPaths() should not be abstract"
abstract public function getPaths(); //OK
public static function getPaths() {} //OK
}
Class:
class AppConfig {
use FileConfig;
public static function getPaths() {
return array(...);
}
}
Call:
AppConfig::getPathForUploads();
It's nessessary to make it static and abstract (to force classes using FileConfig to implement getPaths).
I wonder how is it possible to implement method changing it's static property? Is it a good practice or there are better solutions? Will it one day become illegal?
Thank you
This is fixed in php 7, so the following code works:
<?php
error_reporting(-1);
trait FileConfig {
public static function getPathForUploads() {
echo static::getPaths();
}
abstract static function getPaths();
}
class AppConfig {
use FileConfig;
protected static function getPaths() {
return "hello world";
}
}
AppConfig::getPathForUploads();
http://sandbox.onlinephpfunctions.com/code/610f3140b056f3c3e8defb84e6b57ae61fbafbc9
But it does not actually check if the method in AppConfig is static or not during compilation. You will only get a warning when you try to call the non-static method statically: http://sandbox.onlinephpfunctions.com/code/1252f81af34f71e901994af2531104d70024a685
You do not need to make the method static to force classes using it to implement the method. You can simply use interfaces alongside.
trait FileUploadConfig {
public static function getPathForUploads() {
$paths = static::getPaths();
//etc.
}
}
The trait was left as is. I just took away the functions for the interface.
interface PathConfiguration {
public static function getPaths();
}
The interface forces the class to implement the function. I left the static in there to correspond with the trait's specification.
class AppConfig implements PathConfiguration {
use FileUploadConfig;
public static function getPaths() {
return [];
}
}
To force classes using FileConfig to implement getPaths it's not nessessary to make abstract function static. Static means that it belongs to the class that declared it. Make it protected static, add code from trait and then you could change behaviour by inheritance from your AppConfig class.

Singleton access / PHP Magic method __toString/ printing a static object

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;

Can I use an abstract class instead of a private __construct() when creating a singleton in PHP?

When creating a Singleton in PHP, I ensure that it cannot be instantiated by doing the following:
class Singleton {
private function __construct() {}
private function __clone() {}
public static function getInstance() {}
}
However, I realised that defining a class as 'abstract' means that it cannot be instantiated. So is there anything wrong with doing the following instead:
abstract class Singleton {
public static function getInstance() {}
}
The second scenario allows me to write fewer lines of code which would be nice. (Not that it actually makes much of a difference.)
When creating a singleton in PHP, declaring the __construct and __clone as private ensures that the class cannot be instanciated from the outside : it can still be instanciated from inside its declaration.
When declaring a class as abstract, it can not be instanciated at all ; not even from inside its declaration.
This means your solution would not work : in the second case, your getInstance() method will not be able to instanciate the class -- while it can do so in the first case.
No because then then you can't instantiate the class at all (not even in the static getInstance method). The private constructor in the singleton example just assures, that only the static getInstance method from the same class can access the constructor.
No, you cannot use an abstract class instead of a private __construct() when creating a singleton. But if your intention is to create an Abstract Singleton from which to extend from, you can do so like this:
abstract class Singleton
{
private static $_instances;
public static function getInstance()
{
$className = get_called_class(); // As of PHP 5.3
if(! isset(self::$_instances[$className] )) {
self::$_instances[$className] = new $className();
}
return self::$_instances[$className];
}
protected function __construct( ) {}
final private function __clone( ) {}
final private function __wakeup( ) {}
}
You can then extend from Singleton like this:
class Foo extends Singleton {
protected $_foo = 1;
public function setFoo($i) { $this->_foo = $i; }
public function getFoo() { return $this->_foo; }
}
and
class Bar extends Singleton {
protected $_foo = 1;
public function setFoo($i) { $this->_foo = $i; }
public function getFoo() { return $this->_foo; }
}
and manipulating:
$foo1 = Foo::getInstance();
$foo1->setFoo(5);
$foo2 = Foo::getInstance();
var_dump($foo2);
$bar1 = Bar::getInstance();
var_dump($bar1);
echo new ReflectionObject($foo2);
echo new ReflectionObject($bar1);
However, keep in mind that Singletons are very hard to unit-test and should be avoided if possible. See my answer here for some background:
How to remove multiple instances and just have one instance while multiple function calls in php?
Is there a use-case for singletons with database access in PHP?
It could work if your Singleton::getInstance() is supposed to return an instance of a different class.
abstract class Singleton {
public static function getInstance() {
static $instance = null;
if ( is_null($instance) ) {
$instance = new StdClass; // a different class than 'abstract class Singleton'
$instance->x = time();
}
return $instance;
}
}
$obj = Singleton::getInstance();
But I'd find that confusing. A bit like misusing abstract to combine the complexity of an abstract factory with the restraints of a singleton.

Stacking Static Classes in PHP

Is there a way to make a static class where it has another static class as a member?
E.G. Parent_Class::Child_Class::Member_function();
If you mean nested classes, no. I believe they were going to be introduced at one point but ended up getting dropped.
There is namespace support, however, if that's what you're after.
No.
However, you could use one of PHP's magic methods to do what you want, perhaps:
class ParentClass {
public static function __callStatic($method,$args) {
return call_user_func_array(array('ChildClass',$method),$args);
}
}
class ChildClass {
public static function childMethod() {
...
}
}
ParentClass::childMethod($arg);
Yes, you can have nested static classes in PHP, but it's not pretty, and it takes a bit of extra work. The syntax is a little different than you have.
The trick is to statically initialize the outer class and create a static instance of the inner class.
You can then do one of two things, both are illustrated below.
refer to a static instance of the inner class (child class is actually a misnomer, because there is no inheritance relationship.)
create a static accessor method for the instance of the inner class (this is preferable because it allows for discovery.)
class InnerClass {
public static function Member_function() {
echo __METHOD__;
}
}
class OuterClass {
public static $innerClass;
public static function InnerClass() {
return self::$innerClass;
}
public static function init() {
self::$innerClass = new InnerClass();
}
}
OuterClass::init();
OuterClass::$innerClass->Member_function();
OuterClass::InnerClass()->Member_function();
No, classes are not first-class citizens in PHP so they can't be stored in variables.
You could sort of make a pass through function in your outermost class
class Parent_Class
{
public static $childClass;
public static function callChildMethod( $methodName, array $args=array() )
{
return call_user_func_array( array( self::$childClass, $methodName ), $args );
}
}
class Child_Class
{
public static function hello()
{
echo 'hello';
}
}
Parent_Class::$childClass = 'Child_Class';
Parent_Class::callChildMethod( 'hello' );
PHP does not support nested classes in any form (static or otherwise).

Categories