How to initialize static variables - php

I have this code:
private static $dates = array(
'start' => mktime( 0, 0, 0, 7, 30, 2009), // Start date
'end' => mktime( 0, 0, 0, 8, 2, 2009), // End date
'close' => mktime(23, 59, 59, 7, 20, 2009), // Date when registration closes
'early' => mktime( 0, 0, 0, 3, 19, 2009), // Date when early bird discount ends
);
Which gives me the following error:
Parse error: syntax error, unexpected '(', expecting ')' in /home/user/Sites/site/registration/inc/registration.class.inc on line 19
So, I guess I am doing something wrong... but how can I do this if not like that? If I change the mktime stuff with regular strings, it works. So I know that I can do it sort of like that..
Anyone have some pointers?

PHP can't parse non-trivial expressions in initializers.
I prefer to work around this by adding code right after definition of the class:
class Foo {
static $bar;
}
Foo::$bar = array(…);
or
class Foo {
private static $bar;
static function init()
{
self::$bar = array(…);
}
}
Foo::init();
PHP 5.6 can handle some expressions now.
/* For Abstract classes */
abstract class Foo{
private static function bar(){
static $bar = null;
if ($bar == null)
bar = array(...);
return $bar;
}
/* use where necessary */
self::bar();
}

If you have control over class loading, you can do static initializing from there.
Example:
class MyClass { public static function static_init() { } }
in your class loader, do the following:
include($path . $klass . PHP_EXT);
if(method_exists($klass, 'static_init')) { $klass::staticInit() }
A more heavy weight solution would be to use an interface with ReflectionClass:
interface StaticInit { public static function staticInit() { } }
class MyClass implements StaticInit { public static function staticInit() { } }
in your class loader, do the following:
$rc = new ReflectionClass($klass);
if(in_array('StaticInit', $rc->getInterfaceNames())) { $klass::staticInit() }

Instead of finding a way to get static variables working, I prefer to simply create a getter function. Also helpful if you need arrays belonging to a specific class, and a lot simpler to implement.
class MyClass
{
public static function getTypeList()
{
return array(
"type_a"=>"Type A",
"type_b"=>"Type B",
//... etc.
);
}
}
Wherever you need the list, simply call the getter method. For example:
if (array_key_exists($type, MyClass::getTypeList()) {
// do something important...
}

I use a combination of Tjeerd Visser's and porneL's answer.
class Something
{
private static $foo;
private static getFoo()
{
if ($foo === null)
$foo = [[ complicated initializer ]]
return $foo;
}
public static bar()
{
[[ do something with self::getFoo() ]]
}
}
But an even better solution is to do away with the static methods and use the Singleton pattern. Then you just do the complicated initialization in the constructor. Or make it a "service" and use DI to inject it into any class that needs it.

That's too complex to set in the definition. You can set the definition to null though, and then in the constructor, check it, and if it has not been changed - set it:
private static $dates = null;
public function __construct()
{
if (is_null(self::$dates)) { // OR if (!is_array(self::$date))
self::$dates = array( /* .... */);
}
}

best way is to create an accessor like this:
/**
* #var object $db : map to database connection.
*/
public static $db= null;
/**
* db Function for initializing variable.
* #return object
*/
public static function db(){
if( !isset(static::$db) ){
static::$db= new \Helpers\MySQL( array(
"hostname"=> "localhost",
"username"=> "root",
"password"=> "password",
"database"=> "db_name"
)
);
}
return static::$db;
}
then you can do static::db(); or self::db(); from anywhere.

In PHP 7.0.1, I was able to define this:
public static $kIdsByActions = array(
MyClass1::kAction => 0,
MyClass2::kAction => 1
);
And then use it like this:
MyClass::$kIdsByActions[$this->mAction];

You can't make function calls in this part of the code. If you make an init() type method that gets executed before any other code does then you will be able to populate the variable then.

In my case, I'm using both static and nonstatic class properties, and I might even have main program code referencing the static part of the class before defining the class. Since static portions of classes don't have constructors, just add a manual constructor to initialize any variables requiring nontrivial calculation:
class A
{
static $a; // Initialized by Init()
static function Init()
{
A::$a=nontrivial();
{
}
...
A::Init(); // Initialize static part of class
...
$obj=new A(); // Using initialized class as an object

Here is a hopefully helpful pointer, in a code example. Note how the initializer function is only called once.
Also, if you invert the calls to StaticClass::initializeStStateArr() and $st = new StaticClass() you'll get the same result.
$ cat static.php
<?php
class StaticClass {
public static $stStateArr = NULL;
public function __construct() {
if (!isset(self::$stStateArr)) {
self::initializeStStateArr();
}
}
public static function initializeStStateArr() {
if (!isset(self::$stStateArr)) {
self::$stStateArr = array('CA' => 'California', 'CO' => 'Colorado',);
echo "In " . __FUNCTION__. "\n";
}
}
}
print "Starting...\n";
StaticClass::initializeStStateArr();
$st = new StaticClass();
print_r (StaticClass::$stStateArr);
Which yields :
$ php static.php
Starting...
In initializeStStateArr
Array
(
[CA] => California
[CO] => Colorado
)

Related

PHP Class __Constructor parameters are NULL once function call happened

After all, searching enough in SO I couldn't find out a most generic with best practice solution for PHP __constructor with multiple parameter into a class function
I am trying to define a function inside a PHP class. Where I will be using this function multiple times through a simple function call. Where the function will be having 2 or more parameters.
When I do a function call by passing the parameter, it's just NULL when it reaches the __constructor.
Why it's NULL?
Also, note that there are objects nested inside the function addFruitCheckBox.
What I am doing wrong?
I may also wanted to pass a function call instead of $this->addFruitCheckBoxItemName sometimes.
There are lot of specific problems and solutions in SO. However, I believe this generic question will help me and all, for passing mulitple parameter into __constructor function in a PHP class
ini_set('display_errors', 1);
$_GET['SELECTEDTABNAME'] = 'properties';
/* all include files that are involved in function call within a function will be declared here */
class AddFruitController
{
protected $addFruitCheckBoxItemName;
protected $addFruitCheckBoxLabel;
protected $addFruitMenuItemName;
protected $addFruitChoiceItemName;
protected $addFruitTimeItemName;
public $trustedFruits;
public $trustedFruitsModel;
public $trustedFruitsSpeed;
public $addNewFruit;
public $additionalTub;
public $chooseParent;
public $FruitDown;
public $FruitSell;
public $timeTitle;
public $addFruitbutton;
public function __construct($addFruitCheckBoxItemName, $addFruitCheckBoxLabel, $addFruitMenuItemName, $addFruitTimeItemName)
{
global $interpreterMan, $fetchSeedForSapling;
// var_dump($this->addFruitCheckBoxLabel);
// var_dump($this->addFruitCheckBoxItemName);
$this->trustedFruits = $interpreterMan("Trusted Fruits");
$this->trustedFruitsModel = $interpreterMan("Model");
$this->trustedFruitsSpeed = $interpreterMan("Speed");
$this->addNewFruit = $interpreterMan("New Fruit");
$this->additionalTub = $interpreterMan("Additional Options");
$this->chooseParent = $interpreterMan("Choose Parent");
$this->FruitDown = $interpreterMan("Download Schedule");
$this->FruitSell = $interpreterMan("Install Schedule");
$this->timeTitle = $interpreterMan("Time");
$this->addFruitbutton = $interpreterMan("Add Fruit(s)");
$this->addFruitCheckBoxItemName = $addFruitCheckBoxItemName;
$this->addFruitCheckBoxLabel = $addFruitCheckBoxLabel;
$this->addFruitMenuItemName = $addFruitMenuItemName;
$this->addFruitChoiceItemName = $addFruitChoiceItemName;
var_dump($addFruitChoiceItemName);
$this->addFruitTimeItemName = $addFruitTimeItemName;
}
public function addFruitMenu()
{
global $interpreterMan;
$theWidfetch = new FruitMenu();
$theWidfetch->AssignAddJsCode(false);
$theWidfetch->AssignChoiceOrder(array($interpreterMan("English")));
$theWidfetch->AssignChoiceText(array($interpreterMan("English") => $interpreterMan("English")));
$theWidfetch->AssignGroupHeader($this->addFruitMenuItemName);
$theWidfetch->AssignItemName($this->addFruitMenuItemName);
$theWidfetch->AssignSaveLocation($this->addFruitMenuItemName);
$theWidfetch->AssignValueToUse("ipad");
$theWidfetch->WaterPath(true, true);
}
public function addFruitChoiceTable()
{
global $fetchSeedForSapling, $interpreterMan;
$weekChoiceSelection = new FruitChoiceTable();
$weekChoiceSelection->AssignAddJsCode(false);
$weekChoiceSelection->AssignChoiceOrder(
array("sun", "mon", "tue", "wed", "thu", "fri", "sat"));
$weekChoiceSelection->AssignChoiceText(array(
"sun" => $interpreterMan("SUN"),
"mon" => $interpreterMan("MON"),
"tue" => $interpreterMan("TUE"),
"wed" => $interpreterMan("WED"),
"thu" => $interpreterMan("THU"),
"fri" => $interpreterMan("FRI"),
"sat" => $interpreterMan("SAT"),
));
var_dump($weekChoiceSelection->AssignGroupHeader($this->addFruitChoiceItemName));
$weekChoiceSelection->AssignItemName("Weekday");
$weekChoiceSelection->AssignNumColumns(7);
$weekChoiceSelection->AssignValueToUse($fetchSeedForSapling("dayOfWeek"));
$weekChoiceSelection->WaterPath(true, true);
}
public function addFruitTime()
{
global $fetchSeedForSapling;
$FruitTimeSelect = new FruitTime();
$FruitTimeSelect->AssignGroupHeader($addFruitTimeItemName);
$FruitTimeSelect->AssignItemName($addFruitTimeItemName);
$FruitTimeSelect->AssignValueToUse($fetchSeedForSapling("minuteOfDay"));
$FruitTimeSelect->WaterPath(true, true);
}
public function addFruitCheckBox()
{
global $fetchSeedForSapling;
$addFruitCheckBoxObj = new FruitCheckbox();
$addFruitCheckBoxObj->AssignAddJsCode(false);
$addFruitCheckBoxObj->AssignCheckboxLabel($this->addFruitCheckBoxLabel);
$addFruitCheckBoxObj->AssignItemName($this->addFruitCheckBoxItemName);
$addFruitCheckBoxObj->AssignSaveLocation("somejob");
$addFruitCheckBoxObj->AssignValueToUse($fetchSeedForSapling("somejob"));
$addFruitCheckBoxObj->WaterPath(true, true);
}
}
For creating such complex objects, I suggest you to use Builder Design Pattern instead of assigning properties dynamically and directly.
Note: For better, you can add a layer of interface which Builder classes will implement. And you can have multiple Builder classes which generate different complex objects as per different use cases. Hope this make sense.
Try this code snippet here
<?php
class Builder {
public static function getMyClass($a, $b, $c) {
$myClass = MyClass::getInstance();
$myClass->setA($a);
$myClass->setB($b);
return $myClass;
}
}
class MyClass {
protected $a=0;
protected $b=0;
public static function getInstance() {
$myClass = new MyClass();
return $myClass;
}
function setA($a) {
$this->a = $a;
}
function setB($b) {
$this->b = $b;
}
}
$myClass = Builder::getMyClass("a", "b", "c");
print_r($myClass);
Explanation: In the above mentioned code we have a Builder class which is responsible for building such complex objects.
But still if you are still more towards dynamic assignment approach which nobody recommends, you can see this post
http://php.net/manual/en/language.oop5.decon.php
class MyClass {
protected $a1;
protected $a2;
protected $a3;
public function __construct($a1, $a2, $a3) {
$this->a1 = $a1;
$this->a2 = $a2;
$this->a3 = $a3;
}
}

How do I get the value of a variable in a function inside a private function in a class?

I have a PHP class like the following
<?php
class Test{
var $conf = array('a' => 1, 'b' => 2, c => 3);
private function do_something(){
// Do something Here
function do_something_else(){
// How to get the variable value for $conf ???? o.O
}
}
}
?>
I want to access $conf inside the function do_something_else(). In the upper level functions I am able to access this as $this->conf, but I guess $this would not be available in the inner function. What would be the best possible way to access the variables inside that function?
I cannot pass the values as this function would be called by a built-in function in WordPress CMS, so passing arguments can not be a choice here.
I believe what you need is anonymous function, here is some solutions.
You can do in PHP 5.3:
class Test{
var $conf = array('a' => 1, 'b' => 2, 'c' => 3);
private function do_something(){
// Do something Here
$that = $this;
$do_something_else = function() use($that) {
echo $that->conf;
};
$do_something_else();
}
}
Or use $this directly on anonymous function but only PHP 5.4.
Why not keep it simple
i.e
<?php
class Test{
private $conf;
private function _construct()
{
$this->conf = array('a' => 1, 'b' => 2, c => 3);
}
private function do_something_else(){
// How to get the variable value for $conf ???? o.O
// NOW THIS BIT IS EASY $this->conf;
}
private function do_something(){
// Do something Here
}
}
?>

php static array initialization workaround

I'm not sure what I should be searching to figure out this issue, so I'll show the code and describe the issue:
PHP Code:
<?php
class Foo
{
private static
$defaultSettings = array(
'bar' => new Baz() //error here
);
private
$settings;
public function __construct( $options = null )
{
$this->settings = isset( $options ) ? array_merge( self::$defaultSettings, $options ) : self::$defaultSettings;
}
}
class Baz
{
...code...
}
The Error:
Parse error: syntax error, unexpected T_NEW in [filename] on line [number]
What I'd like to do is have Foo::$defaultSettings contain an instance of an object, but I can't initialize the object when I create the array.
Is there a simpler way around this issue than a static initializer?
Static initializer code for Foo:
//self::init() would be called on the first line of __construct
private static function init()
{
static $initialized;
if ( !$initialized )
{
$initialized = true;
self::$defaultSettings['bar'] = new Baz();
}
}
I feel like there should be a simpler way around this issue than having to run an initializer.
Edit to add:
I could also make the initializer function public and call it immediately after the class definition as Foo::init(); which would reduce the overhead of the __construct function; however, I can't really see a single method call being significant savings.
Class properties cannot evaluate or instantiate anything, unfortunately. The closest you can do is run something from your constructor.

Accessing private/protected properties of an object in anonymous function in PHP

I'm trying to dump elements of an object's private property through an anonymous function - of course I could achieve this in any number of other ways, but this highlights a PHP conundrum I can't solve off the top of my head, short of $foo = $this and using $foo - but THAT won't give me the private stuff, so... suggestions ?
Sample code:
class MyClass
{
private $payload = Array( 'a' => 'A element', 'b' => 'B element');
static $csvOrder = Array('b','a');
public function toCSV(){
$values = array_map(
function($name) use ($this) { return $this->payload[$name]; },
self::$csvOrder
);
return implode(',',$values);
}
}
$mc = new MyClass();
print $mc->toCSV();
I believe there is absolutely no way to do directly what you propose.
However, you can work around it either by making the anonymous method a class method (this is not what you asked for, but it could be a practical solution) or pulling everything you need out of $this explicitly and passing the extracted values into the function:
class MyClass
{
private $payload = Array( 'a' => 'A element', 'b' => 'B element');
static $csvOrder = Array('b','a');
public function toCSV(){
$payload = $this->payload;
$values = array_map(
function($name) use ($payload) { return $payload[$name]; },
self::$csvOrder
);
return implode(',',$values);
}
}
You can hack around the limitation by creating a wrapper that utilizes Reflection to allow you to access all properties and methods. You can use it like this then:
$self = new FullAccessWrapper($this);
function () use ($self) { /* ... */ }
Here a sample implementation of the wrapper, taken from here:
class FullAccessWrapper
{
protected $_self;
protected $_refl;
public function __construct($self)
{
$this->_self = $self;
$this->_refl = new ReflectionObject($self);
}
public function __call($method, $args)
{
$mrefl = $this->_refl->getMethod($method);
$mrefl->setAccessible(true);
return $mrefl->invokeArgs($this->_self, $args);
}
public function __set($name, $value)
{
$prefl = $this->_refl->getProperty($name);
$prefl->setAccessible(true);
$prefl->setValue($this->_self, $value);
}
public function __get($name)
{
$prefl = $this->_refl->getProperty($name);
$prefl->setAccessible(true);
return $prefl->getValue($this->_self);
}
public function __isset($name)
{
$value = $this->__get($name);
return isset($value);
}
}
Obviously the above implementation doesn't cover all aspects (e.g. it can't use magic properties and methods).
As you said yourself, it is private and therefore in accessible.
You can:
Pass $this->payload as a parameter to the anonymous function.
Create a method in the class and use it instead.

PHP - passing variables to classes

I trying to learn OOP and I've made this class
class boo{
function boo(&another_class, $some_normal_variable){
$some_normal_variable = $another_class->do_something();
}
function do_stuff(){
// how can I access '$another_class' and '$some_normal_variable' here?
return $another_class->get($some_normal_variable);
}
}
and I call this somewhere inside the another_class class like
$bla = new boo($bla, $foo);
echo $bla->do_stuff();
But I don't know how to access $bla, $foo inside the do_stuff function
<?php
class Boo
{
private $bar;
public function setBar( $value )
{
$this->bar = $value;
}
public function getValue()
{
return $this->bar;
}
}
$x = new Boo();
$x->setBar( 15 );
print 'Value of bar: ' . $x->getValue() . PHP_EOL;
Please don't pass by reference in PHP 5, there is no need for it and I've read it's actually slower.
I declared the variable in the class, though you don't have to do that.
Ok, first off, use the newer style constructor __construct instead of a method with the class name.
class boo{
public function __construct($another_class, $some_normal_variable){
Second, to answer your specific question, you need to use member variables/properties:
class boo {
protected $another_class = null;
protected $some_normal_variable = null;
public function __construct($another_class, $some_normal_variable){
$this->another_class = $another_class;
$this->some_normal_variable = $some_normal_variable;
}
function do_stuff(){
return $this->another_class->get($this->some_normal_variable);
}
}
Now, note that for member variables, inside of the class we reference them by prefixing them with $this->. That's because the property is bound to this instance of the class. That's what you're looking for...
In PHP, constructors and destructors are written with special names (__construct() and __destruct(), respectively). Access instance variables using $this->. Here's a rewrite of your class to use this:
class boo{
function __construct(&another_class, $some_normal_variable){
$this->another_class = $another_class;
$this->some_normal_variable = $another_class->do_something();
}
function do_stuff(){
// how can I access '$another_class' and '$some_normal_variable' here?
return $this->another_class->get($this->some_normal_variable);
}
}
You need to capture the values in the class using $this:
$this->foo = $some_normal_variable

Categories