class A
{
static $v = "A";
static function echoExtendedStaticVariable() {
echo self::$v;
}
}
class B extends A
{
static $v = "B";
// override A's variable with "B"
}
Why does:
echo B::$v
print "A"?
And how do I get it to print "B"?
Is there a way to do this before PHP 5.3?
B->echoExtendedStaticVariable() == 'A' because self:: is evaluated at compile-time, not run-time. It's as if you wrote A:: instead of self::.
What you want is a feature called "late static binding"--it's "late" because it can determine the class at runtime instead of at compile-time.
You can emulate this (sort-of) in PHP 5.2 using ReflectionClass:
class A
{
static $v = "A";
function echoExtendedStaticVariable() {
$rc = new ReflectionClass($this);
echo $rc->getStaticPropertyValue('v');
}
}
class B extends A
{
static $v = "B";
}
$b = new B();
$b->echoExtendedStaticVariable(); // B
Note that you can only do this if you have access to an instance, so you can't make echoExtendedStaticVariable a static method and expect this to work.
There is no way to do this easily in PHP 5.2 (i.e.: without explicitly overriding each method).
When you call B::echoExtendedStaticVariable, it forwards to A::echoExtendedStaticVariable, the scope changes to the one of A and all bindings about B are gone. No backtrace, no reflection, no magic constants, nothing: it all points to A.
In my opinion, static members should be avoided unless really necessary, and it is rarely the case. It renders your code difficult to extend, since dependency injection is limited and substitution is almost impossible (except in anti- patterns like Singleton).
Related
As I am learning how PHP OOP works, I stumbled upon the following confusion.
class Foo {
static function baz() {
echo 'works';
}
}
# 1
$a = 'Foo';
$a::baz();
# 2
Foo::baz();
PHP manual states that since 5.3.0, it is possible to reference a static class via a string (http://php.net/manual/en/language.oop5.static.php)
What I don't understand is, what is the different between #1 and #2? Aren't they technically the same since both are calling a static function without initiating a class? Where can #1 be applied in practical scenario?
The difference is in a version. Before PHP5.3 you cannot use static methods with variable.
Also, second one 'hide' using of a class. Your IDE could not find class usage.
Also you could use object to call static methods.
class Foo {
static function baz() {
echo 'works';
}
}
eval(
'$a = "Foo";
$a::baz();');
eval(
'$a = new Foo();
$a::baz();');
eval(
'Foo::baz();');
http://3v4l.org/WOK44
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;`
I'm getting an error that I think is because I've made some kind of mistake in a refactoring, but I can't find documentation on when $this is bound, and my error could be explained by it being bound statically.
Extra points (I can't actually give you extra points) for links to excellent documentation about this kind of thing in php.
[Edit]
The error that I'm getting is telling me that Subclass::$var doesn't exist when I do, for example, echo $this->var in a superclass. The $var exists in the subclass, though.
$this becomes available after you've called the constructor. Logically you can't use $this in a static function.
Aside from calling $this in a static function there isn't a whole lot that can go wrong timing wise as there is simply no way in PHP.
What exactly is the error you're getting? Code would useful too.
This works in PHP:
class A {
public function foo() {
echo $this->bar;
}
}
class B extends A {
public $bar = 1;
}
$b = new B;
$b->foo(); // 1
It works because of the dynamic scope resolution that PHP has (i.e.: scope is resolved at runtime as opposed to compile time). However, I'd recommend against it, because it is really a particularity of the language for one. For second, failing to declare $bar in a subclass would result in an error. I think that a class should only reference members that it is aware of.
The same code, say in C++:
class A {
public:
void foo() {
std::cout << bar;
}
};
class B : public A {
public:
int bar;
B() {
bar = 1;
}
};
...would give you a compile error (In A::foo(): 'bar' was not declared in this scope).
Yes, $this is bound dynamically, as is evidenced by the fact that the output of the following is "foo":
<?php
class Base
{
public function ecc(){
echo $this->subvar;
}
}
class Sub extends Base
{
public $subvar;
public function __construct(){
$this->subvar = 'foo';
$this->ecc();
}
}
new Sub();
?>
In PHP, what do you mean by function overloading and function overriding. and what is the difference between both of them? couldn't figure out what is the difference between them.
Overloading is defining functions that have similar signatures, yet have different parameters. Overriding is only pertinent to derived classes, where the parent class has defined a method and the derived class wishes to override that method.
In PHP, you can only overload methods using the magic method __call.
An example of overriding:
<?php
class Foo {
function myFoo() {
return "Foo";
}
}
class Bar extends Foo {
function myFoo() {
return "Bar";
}
}
$foo = new Foo;
$bar = new Bar;
echo($foo->myFoo()); //"Foo"
echo($bar->myFoo()); //"Bar"
?>
Function overloading is not supported by PHP. It occurs when you define the same function name twice (or more) using different set of parameters. For example:
class Addition {
function compute($first, $second) {
return $first+$second;
}
function compute($first, $second, $third) {
return $first+$second+$third;
}
}
In the example above, the function compute is overloaded with two different parameter signatures. *This is not yet supported in PHP. An alternative is to use optional arguments:
class Addition {
function compute($first, $second, $third = 0) {
return $first+$second+$third;
}
}
Function overriding occurs when you extend a class and rewrite a function which existed in the parent class:
class Substraction extends Addition {
function compute($first, $second, $third = 0) {
return $first-$second-$third;
}
}
For example, compute overrides the behavior set forth in Addition.
Strictly speaking, there's no difference, since you cannot do either :)
Function overriding could have been done with a PHP extension like APD, but it's deprecated and afaik last version was unusable.
Function overloading in PHP cannot be done due to dynamic typing, ie, in PHP you don't "define" variables to be a particular type. Example:
$a=1;
$a='1';
$a=true;
$a=doSomething();
Each variable is of a different type, yet you can know the type before execution (see the 4th one).
As a comparison, other languages use:
int a=1;
String s="1";
bool a=true;
something a=doSomething();
In the last example, you must forcefully set the variable's type (as an example, I used data type "something").
Another "issue" why function overloading is not possible in PHP:
PHP has a function called func_get_args(), which returns an array of current arguments, now consider the following code:
function hello($a){
print_r(func_get_args());
}
function hello($a,$a){
print_r(func_get_args());
}
hello('a');
hello('a','b');
Considering both functions accept any amount of arguments, which one should the compiler choose?
Finally, I'd like to point out why the above replies are partially wrong;
function overloading/overriding is NOT equal to method overloading/overriding.
Where a method is like a function but specific to a class, in which case, PHP does allow overriding in classes, but again no overloading, due to language semantics.
To conclude, languages like Javascript allow overriding (but again, no overloading), however they may also show the difference between overriding a user function and a method:
/// Function Overriding ///
function a(){
alert('a');
}
a=function(){
alert('b');
}
a(); // shows popup with 'b'
/// Method Overriding ///
var a={
"a":function(){
alert('a');
}
}
a.a=function(){
alert('b');
}
a.a(); // shows popup with 'b'
Overloading Example
class overload {
public $name;
public function __construct($agr) {
$this->name = $agr;
}
public function __call($methodname, $agrument) {
if($methodname == 'sum2') {
if(count($agrument) == 2) {
$this->sum($agrument[0], $agrument[1]);
}
if(count($agrument) == 3) {
echo $this->sum1($agrument[0], $agrument[1], $agrument[2]);
}
}
}
public function sum($a, $b) {
return $a + $b;
}
public function sum1($a,$b,$c) {
return $a + $b + $c;
}
}
$object = new overload('Sum');
echo $object->sum2(1,2,3);
Although overloading paradigm is not fully supported by PHP the same (or very similar) effect can be achieved with default parameter(s) (as somebody mentioned before).
If you define your function like this:
function f($p=0)
{
if($p)
{
//implement functionality #1 here
}
else
{
//implement functionality #2 here
}
}
When you call this function like:
f();
you'll get one functionality (#1), but if you call it with parameter like:
f(1);
you'll get another functionality (#2). That's the effect of overloading - different functionality depending on function's input parameter(s).
I know, somebody will ask now what functionality one will get if he/she calls this function as f(0).
Method overloading occurs when two or more methods with same method name but different number of parameters in single class.
PHP does not support method overloading.
Method overriding means two methods with same method name and same number of parameters in two different classes means parent class and child class.
I would like to point out over here that Overloading in PHP has a completely different meaning as compared to other programming languages. A lot of people have said that overloading isnt supported in PHP and by the conventional definition of overloading, yes that functionality isnt explicitly available.
However, the correct definition of overloading in PHP is completely different.
In PHP overloading refers to dynamically creating properties and methods using magic methods like __set() and __get(). These overloading methods are invoked when interacting with methods or properties that are not accessible or not declared.
Here is a link from the PHP manual : http://www.php.net/manual/en/language.oop5.overloading.php
Overloading: In Real world, overloading means assigning some extra stuff to someone. As as in real world Overloading in PHP means calling extra functions. In other way You can say it have slimier function with different parameter.In PHP you can use overloading with magic functions e.g. __get, __set, __call etc.
Example of Overloading:
class Shape {
const Pi = 3.142 ; // constant value
function __call($functionname, $argument){
if($functionname == 'area')
switch(count($argument)){
case 0 : return 0 ;
case 1 : return self::Pi * $argument[0] ; // 3.14 * 5
case 2 : return $argument[0] * $argument[1]; // 5 * 10
}
}
}
$circle = new Shape();`enter code here`
echo "Area of circle:".$circle->area()."</br>"; // display the area of circle Output 0
echo "Area of circle:".$circle->area(5)."</br>"; // display the area of circle
$rect = new Shape();
echo "Area of rectangle:".$rect->area(5,10); // display area of rectangle
Overriding : In object oriented programming overriding is to replace parent method in child class.In overriding you can re-declare parent class method in child class. So, basically the purpose of overriding is to change the behavior of your parent class method.
Example of overriding :
class parent_class
{
public function text() //text() is a parent class method
{
echo "Hello!! everyone I am parent class text method"."</br>";
}
public function test()
{
echo "Hello!! I am second method of parent class"."</br>";
}
}
class child extends parent_class
{
public function text() // Text() parent class method which is override by child
class
{
echo "Hello!! Everyone i am child class";
}
}
$obj= new parent_class();
$obj->text(); // display the parent class method echo
$obj= new parent_class();
$obj->test();
$obj= new child();
$obj->text(); // display the child class method echo
There are some differences between Function overloading & overriding though both contains the same function name.In overloading ,between the same name functions contain different type of argument or return type;Such as:
"function add (int a,int b)" & "function add(float a,float b);
Here the add() function is overloaded.
In the case of overriding both the argument and function name are same.It generally found in inheritance or in traits.We have to follow some tactics to introduce, what function will execute now.
So In overriding the programmer follows some tactics to execute the desired function where in the overloading the program can automatically identify the desired function...Thanks!
Overloading: Declaring a function multiple times with a different set of parameters like this:
<?php
function foo($a) {
return $a;
}
function foo($a, $b) {
return $a + $b;
}
echo foo(5); // Prints "5"
echo foo(5, 2); // Prints "7"
?>
Overriding: Replacing the parent class's method(s) with a new method by redeclaring it like this:
<?php
class foo {
function new($args) {
// Do something.
}
}
class bar extends foo {
function new($args) {
// Do something different.
}
}
?>
PHP 5.x.x does not support overloading this is why PHP is not fully OOP.
If I have a function:
function this($a){
return $a;
}
If I wanted to redefine the function, would it be as simple as rewriting it?
function this($a, $b){ //New this function
return $a * $b;
}
Nope, that throws an error:
Fatal error: Cannot redeclare foo()
The runkit provides options, including runkit_function_rename() and runkit_function_redefine().
If you mean overloading in a Java sense, then the answer is no, this is not possible.
Quoting the PHP manual on functions:
PHP does not support function overloading, nor is it possible to undefine or redefine previously-declared functions.
You could use the runkit extension but usage of runkit in production scenarios is generally considered doubtful practice. If you want to exchange algorithms at runtime, have a look at the Strategy pattern or Anonymous functions instead.
If by redefine you mean add to an existing userland function, refactor, substitute or rewrite, then yes: it is as simple as you've shown. Just add the additional code to the function, but make sure you set a default for backwards compatibility.
Another option would be to use http://antecedent.github.io/patchwork
Patchwork is a PHP library that makes it possible to redefine user-defined functions and methods at runtime, loosely replicating the functionality runkit_function_redefine in pure PHP 5.3 code, which, among other things, enables you to replace static and private methods with test doubles.
You can't redefine or 'undefine' a function in PHP (without resorting to third-party modules). However, you can define a function conditionally.
So, if you know function A can be defined elsewhere, but not always, you can wrap it like this:
if (!function_exists('A')) {
function A() {
// default A implementation
}
}
Then you only need to make sure the implementation you want is encountered first:
function A() {
// another A implementation
}
I've got a library of functions that sometimes I just don't want invoked while I'm testing (typically database updates). If I have, for example, a few different db update functions that are all over the code. instead of commenting out the code, I just create a special class (e.g. class foo {}). Define a global variable (e.g., $DEBUG) and a dummy function (e.g., function dummy {}).
Inside foo define all the (public static) functions you need to mimic as
$fn = isset($DEBUG) ? 'dummy' : 'real function';
return call_user_func_array($fn,func_get_args());
Plus you have the advantages of now doing other things, like logging the calls and parameters.
Then simply replace all your calls to real_function(...) with foo::real_function(...). Usually just a simple search/replace (or leave it there; depending on what's going on in the function and how often it's getting called the overhead may be irrelevant).
I have good news and bad news.
The good news
It is possible (link(s) below).
The nadnews
There are 2 bad news:
By default, only userspace functions may be removed, renamed, or modified. In order to override internal functions, you must enable the runkit.internal_override setting in php.ini.
And the second bad news: You havbe to sacrifice code readability.
Example:
<?php
function this($a){
return $a;
}
echo this(0);
$f_name = 'this';
$f_args = '$a';
$f_code = 'return $a*$b;';
runkit_function_redefine($f_name, f_args, f_code);
echo this(1,3);
Oh, and one more thing, using this as a name for a function may create confusion, due to the methods of a object of a class being able to use this.something to reffer to the variable something that is in the method and have the same name as the variable something from the object itself. Here is an example
<?php
class theclass{
$a = 'a';
function a($a){
echo $a;
$a = this.$a;
}
}
theclass $object = new theclass();
$object -> a('b'); // will echo: ab
You cannot redeclare functions, without runtime hacking, but in various situations you may, in fact, redefine them.
Namely, if they are stored in a variable. Though, under the hood this is really reassigning the symbol to a new function.
$action['doSomething'] = function($arguments){
return 'false';
};
$action['doSomething'] = function($arguments){
return var_export($arguments,true);
};
echo $action['doSomething']('Hello world');
There is also the case of inheritance.
namespace CoolCorp\AwesomeGame;
class World{
const TILE_SIZE = 8; // size in pixels of an N x N square
const GAME_TICK = 25; // milliseconds between action sequence frames
const UP = 1;
const DOWN = 2;
const LEFT = 3;
const RIGHT = 4;
.
.
}
class Character2D{
const WALK = 1;
const RUN = 2;
public $mode=1;
public $x=0;
public $y=0;
public $next_x=0;
public $next_y=0;
.
.
public function move($direction){
$selected_mode = self::$mode == self::RUN ?
__NAMESPACE__ . '\RunMode'
: __NAMESPACE__ . '\WalkMode';
class_alias($selected_mode, 'game_movement');
switch($direction){
case UP: game_movement::up($this); break;
case DOWN: game_movement::down($this); break;
case LEFT: game_movement::left($this); break;
case RIGHT: game_movement::right($this); break;
}
$this->AnimateNextPositionAsync(WORLD::GAME_TICK);
}
public function move_Alternative($direction){
$game_movement = self::$mode == self::RUN ?
__NAMESPACE__ . '\RunMode'
: __NAMESPACE__ . '\WalkMode';
switch($direction){
case UP: $game_movement::up($this); break;
case DOWN: $game_movement::down($this); break;
case LEFT: $game_movement::left($this); break;
case RIGHT: $game_movement::right($this); break;
}
$this->AnimateNextPositionAsync(WORLD::GAME_TICK);
}
.
.
}
class WalkMode{
public static function up($actor){
$actor->next_y -= World::TILE_SIZE;
};
public static function down($actor){
$actor->next_y += World::TILE_SIZE;
};
public static function left($actor){
$actor->next_x -= World::TILE_SIZE;
};
public static function right($actor){
$actor->next_x += World::TILE_SIZE;
};
}
class RunMode extends WalkMode{
public static function up($actor){
$actor->next_y -= World::TILE_SIZE*2;
};
public static function down($actor){
$actor->next_y += World::TILE_SIZE*2;
};
public static function left($actor){
$actor->next_x -= World::TILE_SIZE*2;
};
public static function right($actor){
$actor->next_x += World::TILE_SIZE*2;
};
}
A bit contrived but illustrative of how you may redefine a function in a child class and use to achieve a goal. The second example assumes you are not using an ancient PHP version.
You can't have both functions declared at the same time, that will give an error.
You can't redeclare it. If your question is just about overloading that example, how about:
function this($a, $b=1)
{
return $a * $b;
}
Setting an appropriate default to any new arguments that you add might help for backwards compatibility, i.e.:
function this($a, $b=1){ //New this function with a sane default.
return $a * $b;
}
I also recommend, for clarity, generally avoiding using this for function/variable names.