`static` keyword inside function? - php

I was looking at the source for Drupal 7, and I found some things I hadn't seen before. I did some initial looking in the php manual, but it didn't explain these examples.
What does the keyword static do to a variable inside a function?
function module_load_all($bootstrap = FALSE) {
static $has_run = FALSE

It makes the function remember the value of the given variable ($has_run in your example) between multiple calls.
You could use this for different purposes, for example:
function doStuff() {
static $cache = null;
if ($cache === null) {
$cache = '%heavy database stuff or something%';
}
// code using $cache
}
In this example, the if would only be executed once. Even if multiple calls to doStuff would occur.

Seems like nobody mentioned so far, that static variables inside different instances of the same class remain their state. So be careful when writing OOP code.
Consider this:
class Foo
{
public function call()
{
static $test = 0;
$test++;
echo $test . PHP_EOL;
}
}
$a = new Foo();
$a->call(); // 1
$a->call(); // 2
$a->call(); // 3
$b = new Foo();
$b->call(); // 4
$b->call(); // 5
If you want a static variable to remember its state only for current class instance, you'd better stick to a class property, like this:
class Bar
{
private $test = 0;
public function call()
{
$this->test++;
echo $this->test . PHP_EOL;
}
}
$a = new Bar();
$a->call(); // 1
$a->call(); // 2
$a->call(); // 3
$b = new Bar();
$b->call(); // 1
$b->call(); // 2

Given the following example:
function a($s){
static $v = 10;
echo $v;
$v = $s;
}
First call of
a(20);
will output 10, then $v to be 20. The variable $v is not garbage collected after the function ends, as it is a static (non-dynamic) variable. The variable will stay within its scope until the script totally ends.
Therefore, the following call of
a(15);
will then output 20, and then set $v to be 15.

Static works the same way as it does in a class. The variable is shared across all instances of a function. In your particular example, once the function is run, $has_run is set to TRUE. All future runs of the function will have $has_run = TRUE. This is particularly useful in recursive functions (as an alternative to passing the count).
A static variable exists only in a
local function scope, but it does not
lose its value when program execution
leaves this scope.
See http://php.net/manual/en/language.variables.scope.php

To expand on the answer of Yang
If you extend a class with static variables, the individual extended classes will hold their "own" referenced static that's shared between instances.
<?php
class base {
function calc() {
static $foo = 0;
$foo++;
return $foo;
}
}
class one extends base {
function e() {
echo "one:".$this->calc().PHP_EOL;
}
}
class two extends base {
function p() {
echo "two:".$this->calc().PHP_EOL;
}
}
$x = new one();
$y = new two();
$x_repeat = new one();
$x->e();
$y->p();
$x->e();
$x_repeat->e();
$x->e();
$x_repeat->e();
$y->p();
outputs:
one:1
two:1
one:2
one:3 <-- x_repeat
one:4
one:5 <-- x_repeat
two:2
http://ideone.com/W4W5Qv

static variable in a function means that no matter how many times you call the function, there's only 1 variable.
<?php
class Foo{
protected static $test = 'Foo';
function yourstatic(){
static $test = 0;
$test++;
echo $test . "\n";
}
function bar(){
$test = 0;
$test++;
echo $test . "\n";
}
}
$f = new Foo();
$f->yourstatic(); // 1
$f->yourstatic(); // 2
$f->yourstatic(); // 3
$f->bar(); // 1
$f->bar(); // 1
$f->bar(); // 1
?>

Inside a function, static means that the variable will retain its value each time the function is called during the life of the page load.
Therefore in the example you've given, if you call a function twice, if it set $has_run to true, then the function would be able to know that it had previously been called because $has_run would still be equal to true when the function starts the second time.
The usage of the static keyword in this context is explained in the PHP manual here: http://php.net/manual/en/language.variables.scope.php

Related

Are Unamed Variables in Function Call Static

So we call some function in PHP:
do_something('foodabaa');
function do_something($subject)
{
static $pattern = '~foo~';
return preg_replace($pattern, 'bar', $subject);
}
Is the replacement value bar static, or is it dynamic so each call to the function reinitializes it?
By all means add info about other programming languages besides PHP.
From PHP documentation (Example #5):
function test()
{
static $a = 0;
echo $a."\n\r";
$a++;
}
Now, $a is initialized only in first call of function and every time
the test() function is called it will print the value of $a and
increment it.
So if you will call it twice:
test();
test();
Return will be:
0
1
Lets back to your example. There is same situation, $pattern will be initialized just once.
Inside C/C++
void foo()
{
static int a = 0;
printf("%d", a);
x++;
}
int main()
{
foo();
foo();
return 0;
}
Output will be:
0
1
That's the common behavior in many languages which are using static variables.

In PHP, is it possible to have a function within a class that's non-static, but also isn't an instance function?

In PHP, is it possible to have a function within a class that's non-static, but also isn't an instance function?
For example, if I have the following:
class A
{
public $i;
function setValue($val) {
$this->i = $val;
}
}
$a1 = new A;
$a1->setValue(5);
echo $a1->i; // result: 5
$a2 = new A;
$a2->setValue(2);
echo $a2->i; // result: 2
Can I add a function to that class that can have "visibility" of all instances of itself so I can do something like so (which I know doesn't work, but communicates my thought):
class A
{
public $i;
function setValue($val) {
$this->i = $val;
}
function getTotal() {
return sum($this->i); // I know sum() isn't a built-in function, but it helps explain what I want. I'm not sure if $this makes sense here too.
}
}
$a1 = new A;
$a1->setValue(5);
echo $a1->i; // result: 5
$a2 = new A;
$a2->setValue(2);
echo $a2->i; // result: 2
echo A::getTotal(); // returns: 7
I guess A::getTotal() means getTotal() would need to be static, but if it was static then it wouldn't then be able to "see" each class instance.
Is this type of thing possible, and what's the correct terminology I should be using?
No, there is no built-in instance enumeration, you will need to keep references to each instantiated object yourself. You can keep an array of instances in a static property of the class and populate it in your __construct(). You can then have a static method loop over this array and process all instances.
I think you would like something like this:
class A
{
public $i;
function setValue($val) {
$this->i = $val;
}
}
$a1 = new A;
$a1->setValue(5);
echo $a1->i; // result: 5
$a2 = new A;
$a2->setValue(2);
echo $a2->i; // result: 2
$total = 0;
foreach( get_defined_vars() as $name => $obj ) {
if ( $obj instanceof A ) {
$total += $obj->i;
}
}
echo $total; // returns: 7
The function you need here is "get_defined_vars". But it only gets the variables within the current scope!
Just make the class member of the sum static as well. If you do this, then you will need to make sure it's maintained properly within each class (i.e. setValue needs to update that sum appropriarely).
This is probably not a great way to do things, though. I think it would get pretty confusing. In what context do you need the sum that you don't have access to all the instances?
Are you looking for a protected function foo($s){...} which the class can use but cannot be accessed from the outside? (PHP5 only)

Static variables in PHP

I have found different information regarding static variables in PHP but nothing that actually explains what it is and how it really works.
I have read that when used within a class that a static property cannot be used by any object instantiated by that class and that a static method can be used by an object instantiated by the class?
However, I have been trying to research what a static variable does within a function that is not in a class. Also, does a static variable within a function work somewhat like closure in javascript or am I totally off in this assumption?
I have read that when used within a class that a static property cannot be used by any object instantiated by that class
It depends on what you mean by that. eg:
class Foo {
static $my_var = 'Foo';
}
$x = new Foo();
echo $x::$my_var; // works fine
echo $x->my_var; // doesn't work - Notice: Undefined property: Foo::$my_var
and that a static method can be used by an object instantiated by the class???
Yes, an instantiated object belonging to the class can access a static method.
The keyword static in the context of classes behave somewhat like static class variables in other languages. A member (method or variable) declared static is associated with the class and rather than an instance of that class. Thus, you can access it without an instance of the class (eg: in the example above, I could use Foo::$my_var)
However, I have been trying to research what a static variable does within a function that is not in a class.
Also, does a static variable within a function work somewhat like closure in javascript or am I totally off in this assumption.
Outside of classes (ie: in functions), a static variable is a variable that doesn't lose its value when the function exits. So in sense, yes, they work like closures in JavaScript.
But unlike JS closures, there's only one value for the variable that's maintained across different invocations of the same function. From the PHP manual's example:
function test()
{
static $a = 0;
echo $a;
$a++;
}
test(); // prints 0
test(); // prints 1
test(); // prints 2
Reference: static keyword (in classes), (in functions)
static has two uses in PHP:
First, and most commonly, it can be used to define 'class' variables/functions (as opposed to instance variables/functions), that can be accessed without instantiating a class:
class A {
public static $var = 'val'; // $var is static (in class context)
public $other_var = 'other_val'; // non-static
}
echo A::$var; // val
echo A::$other_var // doesn't work (fatal error, undefined static variable)
$a = new A;
echo $a->var // won't work (strict standards)
echo $a->other_var // other_val
Secondly, it can be used to maintain state between function calls:
function a() {
static $i = 0;
$j = 0;
return array($i++, $j++);
}
print_r(a()); // array(0, 0)
print_r(a()); // array(1, 0)
print_r(a()); // array(2, 0)
//...
Note that declaring a variable static within a function works the same regardless of whether or not the function is defined in a class, all that matters is where the variable is declared (class member or in a function).
A static variable in a function is initialized only in the first call of that function in its running script.
At first i will explain what will happen if static variable is not used
<?php
function somename() {
$var = 1;
echo $var . "<br />";
$var++;
}
somename();
somename();
somename();
?>
If you run the above code the output you gets will be 1 1 1 . Since everytime you called that function variable assigns to 1 and then prints it.
Now lets see what if static variable is used
<?php
function somename() {
static $var = 1;
echo $var . "<br />";
$var++;
}
somename();
somename();
somename();
?>
Now if you run this code snippet the output will be 1 2 3.
Note: Static keeps its value and stick around everytime the function is called. It will not lose its value when the function is called.
class Student {
static $total_student = 0;
static function add_student(){
return Student::$total_student++;
}
}
First: for the add_student function, the best practice is to use static not public.
Second: in the add_student function, we are using Student::$total_student,not use $this->total_student. This is big different from normal variable.
Third:static variable are shared throughout the inheritance tree.
take below code to see what is the result:
class One {
static $foo ;
}
class Two extends One{}
class Three extends One{}
One::$foo = 1;
Two::$foo = 2;
Three::$foo = 3;
echo One::$foo;
echo Two::$foo;
echo Three::$foo;`

Restricting variable access

I need to have a variable that only one function can write (let's call that function a) and that only one other function can read (let's call that function b). Is that possible?
You could use a static variable:
function foo($val=null) {
static $var = null;
if (!is_null($var)) $var = $val;
return $val;
}
Here $var is only visible inside the function foo and is maintained throughout multiple calls:
foo(123);
echo foo(); // 123
foo(456);
echo foo(); // 456
Or use a class with a private member and access/modify it with public methods:
class A {
private $var;
public function setVar($val) {
$this->var = $val;
}
public function getVar() {
return $this->var;
}
}
With this the private member var is only visible to a particular instance of this class:
$obj1 = new A();
$obj1->setVar(123);
$obj2 = new A();
$obj2->setVar(456);
echo $obj1->getVar(); // 123
echo $obj2->getVar(); // 456
If you make the member static, then there is just one for the class instead of for each instance:
class A {
private static $var;
public function setVar($val) {
self::$var = $val;
}
public function getVar() {
return self::$var;
}
}
$obj1 = new A();
$obj1->setVar(123);
$obj2 = new A();
$obj2->setVar(456);
echo $obj1->getVar(); // 456
echo $obj2->getVar(); // 456
You can use a static abstract class.
abstract class Settings
{
private static var $_settings = array();
public static function get($key,$default = false)
{
return isset(self::$_settings[$key]) ? self::$_settings[$key] : $default;
}
public static function set($key,$value)
{
self::$_settings[$key] = $value;
}
}
Example Usage:
Settings::set('SiteName',`SomeResult`);
echo Settings::get('SiteName');
Since 5.3.0, you can use anonymous functions as closures. The advantage here, is that you can hold on to b... which is returned by a... and fire it off when you're ready:
<?php
function a()
{
// Only a() can write to $myVar
$myVar = 42;
$b = function() use ($myVar)
{
// $b can read $myVar
// no one else can
return $myVar;
};
return $b;
}
// get $b
$test = a();
// use $b
echo $test();
?>
Another solution before 5.3.0, but here a has to fire b which may not be that practical:
You can simply create an internal variable and pass it as an argument. You can do this inside a class, or just inside simple functions:
function a()
{
// ...
// Write the variable that
// only this function can write to
$thisVar = 1;
b($thisVar);
//...
}
function b($myVar)
{
// ...
// Do stuff w $myVar, a copy of $thisVar
// Changing $myVar has no effect on $thisVar
//
}
Do you mean friend functions? Because I'd love to be able to do that. So far I haven't found an easy way though (although you could try using Reflection, but that seems like way to much effort).
For me, it usually hasn't been an issue of maintaining data integrity / encapsulation, but of keeping the list of public methods (which is kinda like a class's API) free of clutter. A perfect framework should be easy to use, have obvious function names etc etc etc. Methods intended for use by a single other method really mess things up. The "solution" I've taken to is prefixing those function names by one or two underscores and writing "intended for internal use only" or something to that extent in the comments.

Reset Class Instance Variables via Method

Does anyone know how to reset the instance variables via a class method. Something like this:
class someClass
{
var $var1 = '';
var $var2 = TRUE;
function someMethod()
{
[...]
// this method will alter the class variables
}
function reset()
{
// is it possible to reset all class variables from here?
}
}
$test = new someClass();
$test->someMethod();
echo $test->var1;
$test->reset();
$test->someMethod();
I know I could simply do $test2 = new SomeClass() BUT I am particularly looking for a way to reset the instance (and its variables) via a method.
Is that possible at all???
You can use reflection to achieve this, for instance using get_class_vars:
foreach (get_class_vars(get_class($this)) as $name => $default)
$this -> $name = $default;
This is not entirely robust, it breaks on non-public variables (which get_class_vars does not read) and it will not touch base class variables.
Yes, you could write reset() like:
function reset()
{
$this->var1 = array();
$this->var2 = TRUE;
}
You want to be careful because calling new someClass() will get you an entirely new instance of the class completely unrelated to the original.
this could be easy done;
public function reset()
{
unset($this);
}
Sure, the method itself could assign explicit values to the properties.
public function reset()
{
$this->someString = "original";
$this->someInteger = 0;
}
$this->SetInitialState() from Constructor
Just as another idea, you could have a method that sets the default values itself, and is called from within the constructor. You could then call it at any point later as well.
<?php
class MyClass {
private $var;
function __construct() { $this->setInitialState(); }
function setInitialState() { $this->var = "Hello World"; }
function changeVar($val) { $this->var = $val; }
function showVar() { print $this->var; }
}
$myObj = new MyClass();
$myObj->showVar(); // Show default value
$myObj->changeVar("New Value"); // Changes value
$myObj->showVar(); // Shows new value
$myObj->setInitialState(); // Restores default value
$myObj->showVar(); // Shows restored value
?>

Categories