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;
}
Related
I have a class named testclass and several functions in it. They all need to access one predefined variable $need_to_have. I want to define it within the class, but how?
Example:
class testclass {
// This won't work:
private static $need_to_have = get_some_info();
public static testfunction1() {
// Do Something with $need_to_have
}
public testfunction2 () {
// Do something else with $need_to_have
}
}
Forgot to mention: I want to have it privat and I'm calling the variable only on static functions, so I can't use the constructor.
You can't do that, because you can't initialize class properties with non-constant expressions.
What you can do is put an accessor method between you and the property, e.g.:
class testclass {
private static $need_to_have;
private static $need_to_have_initialized;
public static testfunction1()
{
// Do Something with getNeedToHave()
}
private static function getNeedToHave()
{
if (!self::$need_to_have_initialized) {
self::$need_to_have = get_some_info();
self::$need_to_have_initialized = true;
}
return self::$need_to_have;
}
}
If there is a constant value that get_some_info is guaranteed to never return, you can use that to initialize $need_to_have; this will allow you to get rid of the helper property $need_to_have_initialized:
// example: get_some_info() never returns false
private static $need_to_have = false;
private static function getNeedToHave()
{
if (self::$need_to_have === false) {
self::$need_to_have = get_some_info();
}
return self::$need_to_have;
}
Another possible modification (improvement?) is to make the property (and the "initialized" flag, if applicable) local static variables inside getNeedToHave; this way they won't even be visible from anywhere within the class itself:
private static function getNeedToHave()
{
static $need_to_have = false;
if ($need_to_have === false) {
$need_to_have = get_some_info();
}
return $need_to_have;
}
This, pretty much, has a lot of ways to do it.
The most popular way here is having a so called getter (accessor) method, which will return the current information regarding the property and it still can be private.
class TestClass {
private static $myVar = 5;
public static getMyVar() {
return self::$myVar;
}
}
So, with proper autoloader, across all your application, you will be able to call
TestClass::getMyVar();
And, as you stated in the comments, nobody will have access to change it from outside the class.
However, it could be considered bad practice, not only for the static way, as also that you should not refer to a class which you have nothing coupled to it, only to retrieve information.
Best way here is to implement registry pattern, where you can register information to the global space.
Make a separated class which implements the Registry design pattern, and maybe set some constraints, so once setted your myVar nobody can reset it, on order to be able to use the following syntax
Registry::get('myVar');
This, of course, will give you the opportunity to put some more logic in that property before registering it into the globalspace, because, defining a property, might make you troubles regarding some definitions.
Make it a property of the class, set it once and use it everywhere:
class testclass
{
public static $need_to_have;
public function __construct()
{
//$this->need_to_have=1;
// Or rather the value returned by
// whatever it is you are doing with it
$this->need_to_have=$this->setNeed();
}
public function testfunction1()
{
// Do Something with $need_to_have
echo $this->need_to_have
}
public function testfunction2 ()
{
echo $this->need_to_have
}
public function setNeed()
{
$x=4;
$y=6;
$ret=$x*$y;
return $ret;
}
}
There is no (object oriented) way to "make variable classwide accessable". But it's not needed.
What you are looking for are object and class properties or class constants.
class TestClass {
const TEST_CLASS_CONSTANT = 'foo';
private static $testClassProperty;
// or with value: private static $testClassProperty = 'bar';
private $testObjectProperty;
// or with value: private $testObjectProperty = 'baz';
// This won't work
// private static $need_to_have = get_some_info();
// -- since you only can execute functions/methods outside of class structure
// or within other functions/methods.
public function testMethod() {
// Writable access to TEST_CLASS_CONSTANT: not possible, since it's a constant.
// Writable access to $testClassProperty: possible with keywords self, parent, and static.
self::$testClassProperty = 'newbar';
// Writable access to $testObjectProperty: possible with keywords this or parent.
$this->testClassProperty = 'newbaz';
// Readable access to TEST_CLASS_CONSTANT: possible with keywords self, parent, and static.
echo self::TEST_CLASS_CONSTANT;
echo PHP_EOL;
// Readable access to $testClassProperty: possible with keywords self, parent, and static.
echo self::$testClassProperty;
echo PHP_EOL;
// Readable access to $testObjectProperty: possible with keywords this or parent.
echo $this->testClassProperty;
}
}
$testObject = new TestClass();
$testObject->testMethod();
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;
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(..);
Hi i have a little collection of classes some of which should be globally accessible.
I found something similar in Zend_Registry, but reading its code i cant understand how a call to a static function could return an initialized instance of a class...
i need to do something like:
<?php
//index.php
$obj = new myUsefulObject();
$obj->loadCfg("myFile.xml");
$req = new HTTPRequest();
$req->filter("blablabla");
myappp::registerClass("object",$obj);
myappp::registerClass("request",$req);
$c = new Controller();
$c->execute();
?>
Here i have filtered the Request object and i want the controller to be able to reach that already filtered request.
<?php
class Controller
{
function __construct()
{
$this->request = Application::getResource("request");//This must be the filtered var =(
}
}
?>
I don't know how to implement that Application::getResource(), the only thing i know is that it must be a static method because it can't be related to a specific instance.
Aside from static methods, PHP also has static properties: properties that are local to the class. This can be used to implement singletons, or indeed a Registry:
class Registry {
private static $_registry;
public static function registerResource($key, $object)
{
self::$_registry[$key] = $object;
}
public static function getResource($key) {
if(!isset(self::$_registry[$key]))
throw InvalidArgumentException("Key $key is not available in the registry");
return self::$_registry[$key];
}
}
1: You can acess global variables with the global keyword:
$myVar = new SomethingProvider();
class MyClass {
public function __construct() {
global $myVar;
$myVar->doSomething();
}
}
2: You can do the same using the $GLOBALS super-global:
$myVar = new SomethingProvider();
class MyClass {
public function __construct() {
$GLOBALS['myVar']->doSomething();
}
}
3: You can define a singleton class (the wikipedia has a nice example, too).
4: You could add globals as public static members (or private static members with public getters/setters) to a class:
class Constants {
const NUM_RETIES = 3;
}
if ($tries > Constants::NUM_RETRIES) {
# User failed password check too often.
}
class Globals {
public static $currentUser;
}
Globals::$currentUser = new User($userId);
I wouldn't recommend the first two methods, overwriting the values of these global variables unintentionally is too easy.
Seems to me like you might need some form of Singleton design pattern;
Check this out!
Hope it helps!
I have a variable on the global scope that is named ${SYSTEM}, where SYSTEM is a defined constant. I've got a lot of classes with functions that need to have access to this variable and I'm finding it annoying declaring global ${SYSTEM}; every single time.
I tried declaring a class variable: public ${SYSTEM} = $GLOBALS[SYSTEM]; but this results in a syntax error which is weird because I have another class that declares class variables in this manner and seems to work fine. The only thing I can think of is that the constant isn't being recognised.
I have managed to pull this off with a constructor but I'm looking for a simpler solution before resorting to that.
EDIT
The global ${SYSTEM} variable is an array with a lot of other child arrays in it. Unfortunately there doesn't seem to be a way to get around using a constructor...
Ok, hopefully I've got the gist of what you're trying to achieve
<?php
// the global array you want to access
$GLOBALS['uname'] = array('kernel-name' => 'Linux', 'kernel-release' => '2.6.27-11-generic', 'machine' => 'i686');
// the defined constant used to reference the global var
define(_SYSTEM_, 'uname');
class Foo {
// a method where you'd liked to access the global var
public function bar() {
print_r($this->{_SYSTEM_});
}
// the magic happens here using php5 overloading
public function __get($d) {
return $GLOBALS[$d];
}
}
$foo = new Foo;
$foo->bar();
?>
This is how I access things globally without global.
class exampleGetInstance
{
private static $instance;
public $value1;
public $value2;
private function initialize()
{
$this->value1 = 'test value';
$this->value2 = 'test value2';
}
public function getInstance()
{
if (!isset(self::$instance))
{
$class = __CLASS__;
self::$instance = new $class();
self::$instance->initialize();
}
return self::$instance;
}
}
$myInstance = exampleGetInstance::getInstance();
echo $myInstance->value1;
$myInstance is now a reference to the instance of exampleGetInstance class.
Fixed formatting
You could use a constructor like this:
class Myclass {
public $classvar;
function Myclass() {
$this->classvar = $GLOBALS[SYSTEM];
}
}
EDIT: Thanks for pointing out the typo, Peter!
This works for array too. If assignment is not desired, taking the reference also works:
$this->classvar =& $GLOBALS[SYSTEM];
EDIT2: The following code was used to test this method and it worked on my system:
<?php
define('MYCONST', 'varname');
$varname = array("This is varname", "and array?");
class Myclass {
public $classvar;
function Myclass() {
$this->classvar =& $GLOBALS[MYCONST];
}
function printvar() {
echo $this->classvar[0];
echo $this->classvar[1];
}
};
$myobj = new Myclass;
$myobj->printvar();
?>
The direct specification of member variables can not contain any references to other variables (class {public $membervar = $outsidevar;} is invalid as well). Use a constructor instead.
However, as you are dealing with a constant, why don't you use php's constant or class constant facilities?
You're trying to do something really out-of-the-ordinary here, so you can expect it to be awkward. Working with globals is never pleasant, especially not with your dynamic name selection using SYSTEM constant. Personally I'd recommend you use $GLOBALS[SYSTEM] everywhere instead, or ...
$sys = $GLOBALS[SYSTEM];
... if you're going to use it alot.
You could also try the singleton pattern, although to some degree it is frowned upon in OOP circles, it is commonly referred to as the global variable of classes.
<?php
class Singleton {
// object instance
private static $instance;
// The protected construct prevents instantiating the class externally. The construct can be
// empty, or it can contain additional instructions...
protected function __construct() {
...
}
// The clone and wakeup methods prevents external instantiation of copies of the Singleton class,
// thus eliminating the possibility of duplicate objects. The methods can be empty, or
// can contain additional code (most probably generating error messages in response
// to attempts to call).
public function __clone() {
trigger_error('Clone is not allowed.', E_USER_ERROR);
}
public function __wakeup() {
trigger_error('Deserializing is not allowed.', E_USER_ERROR);
}
//This method must be static, and must return an instance of the object if the object
//does not already exist.
public static function getInstance() {
if (!self::$instance instanceof self) {
self::$instance = new self;
}
return self::$instance;
}
//One or more public methods that grant access to the Singleton object, and its private
//methods and properties via accessor methods.
public function GetSystemVar() {
...
}
}
//usage
Singleton::getInstance()->GetSystemVar();
?>
This example is slightly modified from wikipedia, but you can get the idea. Try googling the singleton pattern for more information
I'd say the first two things that stand out to me are:
You don't need the brackets around the variable name, you can simply do public $system or public $SYSTEM.
While PHP may not always require it it is standard practice to encapsulate non-numeric array indexes in single or double quotes in case the string you're using becomes a constant at some point.
This should be what you're looking for
class SomeClass {
public $system = $GLOBALS['system'];
}
You can also use class constants which would instead be
class SomeClass {
const SYSTEM = $GLOBALS['system'];
}
This can be referenced within the class with 'self::SYSTEM' and externally with 'SomeClass::SYSTEM'.