I'm attempting to access member variables in a child class via the parent class without instantiation.
This is one of my attempts but B::getStatic() fails with Access to undeclared static property.
Is there another solution to this, possibly without static?
class A {
static public function getStatic() {
return self::$myStatic;
}
}
class B extends A {
public static $myStatic = 5;
}
class C extends A {
public static $myStatic = 6;
}
var_dump(B::$myStatic);
var_dump(B::getStatic());
var_dump(C::$myStatic);
var_dump(C::getStatic());
The concept you're running into is called "Late Static Binding." Until PHP 5.3.0, there was no support for this.
If you're running 5.3.0 or higher, update the getStatic() method:
static public function getStatic() {
return static::$myStatic;
}
The others are right, the way your code is it can't be done since the variable doesn't exist at compile time.
The way to do something like this is usually with an abstract class (available in PHP5 and up, it looks like).
Class A would be the abstract class, and would have a getStatic() function. Classes B and C would extend A and have definitions for the getStatic() function. This way, when you call getStatic() you will get the value the subclass defines since there is no definition in A.
The caveat to this approach is that you can't instantiate A since it's abstract. You would ALWAYS have to make a B or a C (or a subclass there-of).
You could also make a setter in A and have the subclasses use it to set the value (instead of an '='s). That would let you instantiate A and it could set the value if it ever needs to. You might be able to make the setter private so it can't be called directly, I don't know if subclasses can use private functions in PHP.
You have a mismatch between the declaration of the function and variable.
Either you need to move the declaration of the function to B
or
move the declaration of the variable to A.
Class B inherits the properties from class A instead of the reverse.
Why don’t you use B::$myStatic like in your example?
You have to move myStatic into A. Your method getStatic in A can't access a variable that does not exist in A.
From the PHP manual:
Static references to the current class
like self:: or __CLASS__ are resolved
using the class in which the function
belongs, as in where it was defined:
So because the method is defined in A, when you call getStatic() on B or C it is trying to return a::$myStatic, which doesn't exist. Even if it did exist you would only ever get that value back, not any overridden value in a subclass.
A solution is Late Static Bindings, but this is only available in PHP 5.3 which is not yet released.
$myStatic must be declared static in class A: See here.
class A {
public static $myStatic = 5;
}
class B extends A {
public static $myStatic = 3;
}
class C extends A {
public static $myStatic = 1;
}
Then just use B::$myStatic ...
Related
I have a number of PHP classes inheriting a single base class. This base class offers up a static method, let's call it methodA() that can be overridden in each class, but in practice won't be overridden very much. Each class has a static variable, let's call it name that is different, but methodA() needs to be able to act based on name differently for each class. I'm new to object oriented PHP, so I'm not exactly sure how best to do this.
In Java I would make a property on the base class and then define it in the constructor method which I would then call via super(), but I'm not sure how best to do this based on static data. Am I on the right track? What would be the best way to accomplish this?
This answer was thanks to #AlexBlex.
PHP provides a feature called Late Static Bindings that allow exactly this behavior.
As of PHP 5.3.0, PHP implements a feature called late static bindings which can be used to reference the called class in a context of static inheritance.
In the example provided in the question, the way to do this would be as such:
class Base {
public static function methodA() {
return static::$name;
}
}
class A extends Base {
public static $name = "Apple";
}
class B extends Base {
public static $name = "Box";
}
You can then call the function as such with the expected results:
echo(A::methodA()); // "Apple"
echo(B::methodA()); // "Box"
This example runs in PHP 7.
I encountered the following structure:
// parent class
class A
{
public function myFunc1()
{
$this->myFunc2();
}
private function myFunc2()
{
echo "called from class A";
}
}
// sub-class
class B extends A
{
private function myFunc2()
{
echo "called from class B";
}
}
$foo = new B();
$foo->myFunc1();
I expected, since there is no myFunc1() in class B, that the parent-function is called. This seems to be correct.
Now, to play it safe, I var_dump $this in myFunc1() and it shows, that this is an object from type B.
From my understanding, it should call myFunc2() from the Class B, but this isn't happening. It is calling the method from class A.
called from class A
instead of
called from class B
Yes, the functions are private and if I change it to protected, it works as expected. But private implies, that I have access to this function(s), when I'm in the specific context, doesn't it?
Private functions are only available within the class they are defined in, not in sub classes.
This means that your Object has two completely different functions, that happen to have the same name. Object B is aware of having one of them while Object A is only aware of having the other one. They do not interact in any way.
Since these functions are entirely private to the specific class they were defined in, there is no way to override them, or for any other class to call them.
If you need behavior that allows you to override how the class works, you'll have to use protected instead, which is designed specifically to be callable and changeable from extensions (and as such is a completely different beast all-together).
private always belongs to the same class you can't inherit it. That's the reason why myFunc1() calls myFunc2() from class A. If you want to overwrite it you have to change the visibility to protected.
In my project, I'm using class inheritance a lot.
Now I notice that my magic getter is not triggering when I want to access a variable in the base class.
Hence the following code:
abstract class A
{
protected $varA;
final public function __get($var)
{
echo $var;
}
}
class B extends A
{
protected $varB;
}
class C extends A
{
public function test()
{
$test = new B();
$test->varB; // Get output
$test->varA; // No output
}
}
$test = new C();
$test->test();
Now I see that you faced with php feature. Visibility of properties relies on classes but not on the objects.
Objects of the same type will have access to each others private and
protected members even though they are not the same instances. This is
because the implementation specific details are already known when
inside those objects.
http://php.net/manual/en/language.oop5.visibility.php#example-208
__get is only triggered if the property does not exist.
varA is a property of you object. The oly problem is that it is protected. thus not accessible from outside your class.
From CHILD class protected var is available. Child class see varA, but varA is null
$varA is a protected variable of Class A.
Class B & C are extensions of Class A.
So $varA exists in an instance of C or B, because protected variables are accessible and assignable in the children of the class they are defined in. That's what they're for.
Since $varA exists, the __get is not triggered.
I'm not sure what you would expect to be different?
Why in PHP you can access static method via instance of some class but not only via type name?
UPDATE: I'm .net developer but i work with php developers too. Recently i've found this moment about static methods called from instance and can't understand why it can be usefull.
EXAMPLE:
class Foo
{
public static Bar()
{
}
}
We can accept method like this:
var $foo = new Foo();
$foo.Bar(); // ??????
In PHP
the class is instantiated using the new keyword for example;
$MyClass = new MyClass();
and the static method or properties can be accessed by using either scope resolution operator or object reference operator. For example, if the class MyClass contains the static method Foo() then you can access it by either way.
$MyClass->Foo();
Or
MyClass::Foo()
The only rule is that static methods or properties are out of object context. For example, you cannot use $this inside of a static method.
Class Do {
static public function test() {
return 0;
}
}
use like this :
echo Do::test();
Why in PHP you can access static method via instance of some class but not only via type name?
Unlike what you are probably used to with .NET, PHP has dynamic types. Consider:
class Foo
{
static public function staticMethod() { }
}
class Bar
{
static public function staticMethod() { }
}
function doSomething($obj)
{
// What type is $obj? We don't care.
$obj->staticMethod();
}
doSomething(new Foo());
doSomething(new Bar());
So by allowing access to static methods via the object instance, you can more easily call a static function of the same name across different types.
Now I don't know if there is a good reason why accessing the static method via -> is allowed. PHP (5.3?) also supports:
$obj::staticMethod();
which is perhaps less confusing. When using ::, it must be a static function to avoid warnings (unlike ->, which permits either).
In PHP, while you're allowed to access the static method by referencing an instance of the class, you don't necessarily need to do so.
For example, here is a class with a static function:
class MyClass{
public static function MyFunction($param){
$mynumber=param*2;
return $mynumber;
}
You can access the static method just by the type name like this, but in this case you have to use the double colon (::), instead of "->".
$result= MyClass::MyFunction(2);
(Please note you can also access the static method via an instance of the class as well using "-->"). For more information: http://php.net/manual/en/language.oop5.static.php
In PHP 7 it seems to be absolutely necessary for you to be able to do $this->staticFunction(). Because, if this code is written within an abstract class and staticFunction() is also abstract in your abstract class, $this-> and self:: deliver different results!
When executing $this->staticFunction() from a (non-abstract) child of the abstract class, you end up in child::staticFunction(). All is well.
However, executing self::staticFunction() from a (non-abstract) child of the abstract class, you end up in parent::staticFunction(), which is abstract, and thusly throws an exception.
I guess this is just another example of badly designed PHP.
Or myself needing more coffee...
Quick code with the question included:
abstract class ClassParent {
public static $var1 = "ClassParent";
}
class ClassChild1 extends ClassParent{
public static function setvar1(){
ClassChild1::$var1 = "ClassChild1";
}
}
class ClassChild2 extends ClassParent{
public static function setvar1(){
ClassChild2::$var1 = "ClassChild2";
}
}
ClassChild1::setvar1();
echo ClassChild2::$var1;
// Returns "ClassChild1". Shouldn't this still be "ClassParent"?
I am assuming that the above is expected behaviour and not a PHP bug. In that case, how could I declare a static variable in the parent class which will be handled separately for the child classes. In other words, I want to have separate static values PER CHILD CLASS. Must I declare the static variable specifically in the child classes or is there perhaps another way?
Thanks!
EDIT: On further investigation, I think what you're asking is not directly possible, even with late static binding. Actually, I am a little surprised.
The answer to this question provides some workarounds.
Original answer:
In a parent class, if you refer to a static variable in the form:
self::$var
It will use that same variable in all inherited classes (so all child classes will be still accessing the variable in the parent class).
This is because the binding for the self keyword is done at compile-time, not run-time.
As of PHP 5.3, PHP supports late static binding, using the static keyword. So, in your classes, refer to the variable with:
static::$var
And 'static' will be resolved to the child class at run-time, so there will be a separate static variable for each child class.
Thanks for this question! I had some problems I couldn't track and this has helped me solve them. :)
You might be interested to know that there is a bug report for this behavior which includes the workaround. In your case this would be:
class ClassChild1 extends ClassParent{
public static function setvar1(){
$tmp = 'x';
static::$var1 =& $tmp; // break reference
// and now this works as expected: (changes only ClassChild1::$var1)
static::$var1 = "ClassChild1";
}
}
// do the same in ClassChild2...
Ugly as hell, I agree - but PHP works as expected this way, plus it has no side effects.
This is indeed a very doubtful (and poorly documented) "feature" in my eyes - let's hope they change it someday.
Ugly solution, but it works.
I've moved static $var1 to a trait that is required to be used in child classes.
It is essentially the same as declaring $var1 in each child class.
However, using this method there is no chance you forget to declare $var1.
trait Var1Trait
{
public static $var1 = "ClassParent";
protected function requiresVar1Trait()
{
}
}
abstract class ClassParent
{
abstract protected function requiresVar1Trait(); // make sure that Var1Trait is used in child classes
}
class ClassChild1 extends ClassParent
{
use Var1Trait;
public static function setvar1()
{
ClassChild1::$var1 = "ClassChild1";
}
}
class ClassChild2 extends ClassParent
{
use Var1Trait;
public static function setvar1()
{
ClassChild2::$var1 = "ClassChild2";
}
}
ClassChild1::setvar1();
echo ClassChild2::$var1;
// Returns "ClassParent" as requested