I have problem about calling a static property of a class inside another class.
Class A {
public $property;
public function __construct( $prop ) {
$this->property = $prop;
}
public function returnValue(){
return static::$this->property;
}
}
Class B extends A {
public static $property_one = 'This is first property';
public static $property_two = 'This is second property';
}
$B = new B( 'property_one' );
$B->returnValue();
I expect to return This is first property But the Output is just the name a parameter input in __construct;
When I print_r( static::$this->property ); the output is just property_one
Just change:
return static::$this->property;
with:
return static::${$this->property};
Maybe like this?
<?php
Class A {
public $property;
public function __construct( $prop ) {
$this->property = $prop;
print static::${$this->property};
}
}
Class B extends A {
public static $property_one = 'This is first property';
public static $property_two = 'This is second property';
}
$B = new B( 'property_one' );
(I mean you can access (print,...) the property this way, but the constructor will return an object anyway.)
There are several issues here:
the static property $property_one is declared in class B, the A class's constructor won't have access to that property, nor can you guarantee this property to be present.
Granted, since PHP 5.3, late static binding is supported, but that doesn't change the fact that you're never going to be sure that some static property that just happens to be called whatever $this->property happens to be assigned. What if it's assigned an object? an int, or float?
You access a static property like this: static::$propery or self::$property. Note the $! When you write static::$this->property, you're expecting this to evaluate to self::property_one. You're clearly missing the $ sign.
The very least you need is self::${$this->property}. Check the PHP manual on variable variables.
You're attempting to return a string from a constructor function, that's not possible. A constructor must, must return an instance of the class. Any return statements that don't will be ignored.
To have access to a static property of a child class in the constructor, you can't but rely on the child's constructor:
Class A
{
public $property;
}
Class B extends A
{
public static $property_one = 'This is first property';
public static $property_two = 'This is second property';
public function __construct( $prop )
{
$this->property = $prop;
print self::${$this->property};
}
}
$B = new B( 'property_one' );
An alternative would be:
Class A
{
public $property;
public function __constructor($prop)
{
$this->property = $prop;
}
public function getProp()
{
return static::${$this->property};
}
}
Class B extends A
{
public static $property_one = 'This is first property';
public static $property_two = 'This is second property';
}
$B = new B( 'property_one' );
$B->getProp();
Related
I'm facing a misunderstanding about what the title describe and i'd like to know if there is another way to achieve what I'm looking for there.
I have an abstract class which declare a static property without value, and I instanciate subclasses from it that are defining the value of that static property. The base class also define another static property value depending of the first one, but the problem is subclasses are losing their first property value for the last one defined in other subclasses and then this second property get the bad value from the parent class.
This code demonstrate it better than I explain:
abstract class A
{
protected static $name;
protected static $path;
public function __construct()
{
static::$path = static::$name."Path";
}
public function getPath()
{
return static::$path;
}
}
class B extends A
{
protected static $name = "B";
}
class C extends A
{
protected static $name = "C";
}
$b = new B();
$c = new C();
echo $b->getPath();
I expected the echo to print "Bpath", but unfortunately it prints "CPath".
If I comment the line that instanciate the C class, then the print is good.
EDIT:
The thing is if i do this code :
abstract class A
{
protected static $name;
protected static $path;
public function __construct()
{
static::$path = static::$name."Path";
}
public function getPath()
{
return static::$path;
}
public function getName()
{
return static::$name;
}
}
class B extends A
{
protected static $name = "B";
}
class C extends A
{
protected static $name = "C";
}
$b = new B();
$c = new C();
echo $b->getName();
The name printed is "B" and good. So the fact of redefining value in subclass property doesn't have the same consequence of doing it in constructor, even if using static:: keyword.
The static property $path is only defined once on class A. Setting static::$path from anywhere will always set A::$path, so the value is shared among all classes.
You'd see a different result if you declared protected static $path; on both child classes, e.g.:
class B extends A {
protected static $name = "B";
protected static $path;
}
Now each class would have its own static $path property and they could be set independently.
It would make much more sense to use an instance property though instead of this bending over backwards with static properties:
abstract class A {
protected static $name;
protected $path;
public function __construct() {
$this->path = static::$name . 'Path';
}
public function getPath() {
return $this->path;
}
}
I'm testing a logic flow by mocking a class and testing for the function call.
function() setUp()
{
$this->shipping_method = $this->getMockBuilder(Wc_Trincargo_Shipping_Method::class)
->getMock();
$this->shipping_method->set_post_data([
'woocommerce_wc-trinicargo-shipping_waybill_password' => 'xxx',
'woocommerce_wc-trinicargo-shipping_waybill_username' => 'xxxx',
'woocommerce_wc-trinicargo-shipping_waybill_customer_id' => uniqid(),
'woocommerce_wc-trinicargo-shipping_waybill_pickupdays' => 2
]);
}
set_post_data is a public method that sets a protected property.
Later down I test to call a another method that needs to check the said protected property. I know they say you can't mock protected and private properties but if the properties are being set by public methods....shouldn't it work?
If you really need to access a protected property within a test and you don't have a getter (nor should you create one purely for a test), you could use reflection.
<?php
class MyClass
{
protected $myProperty;
public function setMyProperty($value)
{
$this->myProperty = $value;
}
}
$a = new MyClass();
$a->setMyProperty('TestValue');
// echo $a->myProperty; Can't do this because it's protected.
$r = new ReflectionProperty('MyClass', 'myProperty');
$r->setAccessible(true);
$value = $r->getValue($a);
echo $value; // 'TestValue'
It is irrelevant that the protected property was sat from a public method. The visibility belongs to the property regardless. If you need to check the value of the property afterwards, create a public getter for that property.
Note that it is useless to test simple getters and setters. You should test what the class does with the values of the properties instead.
Example of a useless test:
class MyClass {
private $prop;
public function setProp($value) {
$this->prop = $value;
}
public function getProp() {
return $this->prop;
}
}
Test
$myClass = new MyClass();
$myClass->setProp('foo');
assertTrue($myClass->getProp() === 'foo');
Example of a class that uses a prop in a meaningful way, which determines the behavior/output of another method:
class MyClass2 {
private $prop;
public function setProp($value) {
$this->prop = $value;
}
public function getPropUpperCase() {
return strtoupper($this->prop);
}
}
Test
$myClass2 = new MyClass();
$myClass2->setProp('foo');
assertTrue($myClass->getPropUpperCase() === 'FOO');
I'm new in OO php, and I'm trying to access $my_array string (or it is a property):
class Something extends MAIN
{
private static $instance;
public static function newInstance()
{
if( !self::$instance instanceof self ) {
self::$instance = new self;
}
return self::$instance;
}
function __construct()
{
parent::__construct();
$my_array = array('test1','test2');
}
}
Tried with this:
$int = Something::newInstance();
echo $int->my_array;
echo Something::my_array
But nothing works. What is the problem? EDIT: I must mention that I shouldn't change anything inside Something class. Or it is impossible to do this without making a change inside Soemthing class?
$my_array is local to the constructor . You'll need to declare it in such a way that it has the scope of class. You'll have to do it as
class Something extends MAIN
{
private static $instance;
public $my_array = array();
// Rest code
}
$my_array is now a local variable in your method (=function in a class) and therefor cannot be read outside of that method. Change it like this to make it a 'property'*) of the object.
class Something extends MAIN
{
private static $instance;
public $my_array;
function newInstance() { ... } // Left out for brevity
function __construct()
{
parent::__construct();
// Use $this to reference the instance, in the way that self references the class.
$this->my_array = array('test1','test2');
}
}
Then use
$int = Something::newInstance();
echo $int->my_array;
*) PHP calls it a property, but in most languages a property is a definition that referes to getter and setter methods or directly to an (often private) variable in the class. In PHP, that variable itself is called a property.
class Something extends MAIN {
private static $instance;
public static $my_array;
public static
function newInstance() {
if (!self::$instance instanceof self) {
self::$instance = new self;
}
return self::$instance;
}
function __construct() {
parent::__construct();
self::$my_array = array('test1', 'test2');
}
}
You can assign a value to $my_array directly without to be in the constructor function.
public static $my_array = array('test1', 'test2');
and remove this line from constructor
self::$my_array = array('test1', 'test2');
When usage:
$int = Something::newInstance();
print_r(Something::$my_array);
What is the difference between using self and static in the example below?
class Foo
{
protected static $bar = 1234;
public static function instance()
{
echo self::$bar;
echo "\n";
echo static::$bar;
}
}
Foo::instance();
produces
1234
1234
When you use self to refer to a class member, you're referring to the class within which you use the keyword. In this case, your Foo class defines a protected static property called $bar. When you use self in the Foo class to refer to the property, you're referencing the same class.
Therefore if you tried to use self::$bar elsewhere in your Foo class but you had a Bar class with a different value for the property, it would use Foo::$bar instead of Bar::$bar, which may not be what you intend:
class Foo
{
protected static $bar = 1234;
}
class Bar extends Foo
{
protected static $bar = 4321;
}
When you call a method via static, you're invoking a feature called late static bindings (introduced in PHP 5.3).
In the above scenario, using self will result in Foo::$bar(1234).
And using static will result in Bar::$bar (4321) because with static, the interpreter takes into account the redeclaration within the Bar class during runtime.
// self
var_dump(Foo::$bar);
// (int) 1234
// static
var_dump(Bar::$bar);
// (int) 4321
You typically use late static bindings for methods or even the class itself, rather than properties, as you don't often redeclare properties in subclasses; an example of using the static keyword for invoking a late-bound constructor can be found in this related question: New self vs. new static
However, that doesn't preclude using static with properties as well.
I have small example showing difference between self and static. Using static:: performs Late Static Binding and thus it binds the variable value from child class.
class A { // Base Class
protected static $name = 'ClassA';
public static function getSelfName() {
return self::$name;
}
public static function getStaticName() {
return static::$name;
}
}
class B extends A {
protected static $name = 'ClassB';
}
echo A::getSelfName(); // ClassA
echo A::getStaticName(); // ClassA
echo B::getSelfName(); // ClassA
echo B::getStaticName(); // ClassB
With self call:
class Phone
{
protected static $number = 123;
public function getNumber()
{
return self::$number;
}
}
class Fax extends Phone
{
protected static $number = 234;
}
// Displays: "123"
echo (new Fax)->getNumber();
You can see above, even though we have overridden the $number with our Fax class, getNumber() still returns 123.
This because we have asked PHP to give us the variable where it was defined in -- which will return Phones variable instead.
If we swap the self call with static, we will get Faxs overridden value instead:
With static call:
class Phone
{
protected static $number = 123;
public function getNumber()
{
// return self::$number;
return static::$number;
}
}
class Fax extends Phone
{
protected static $number = 234;
}
// Displays: "234"
echo (new Fax)->getNumber();
As mentioned one of the main differences is that static allows for late static bindings. One of the most useful scenarios that I found was for creating Base classes for Singleton Classes:
class A { // Base Class
protected static $name = '';
protected static function getName() {
return static::$name;
}
}
class B extends A {
protected static $name = 'MyCustomNameB';
}
class C extends A {
protected static $name = 'MyCustomNameC';
}
echo B::getName(); // MyCustomNameB
echo C::getName(); // MyCustomNameC
Using return static::$name in the Base class will return what was statically attached when it was extended. If you were to use return self::$name then B::getName() would return an empty string as that is what is declared in the Base class.
Maybe this self-explained code helps you:
class Foo
{
protected static $bar = 'parent value';
public static function test()
{
var_dump('I am your father');
var_dump('self:: here means '.self::$bar);
var_dump('static:: here means '.static::$bar);
}
}
class Bar extends Foo
{
protected static $bar = 'child value';
public static function test()
{
parent::Test();
var_dump('I am the child');
var_dump('self:: here means '.self::$bar);
var_dump('static:: here means '.static::$bar);
}
}
Bar::test();
Foo::test();
This produces the following output (I have added Line Breaks for clarity):
'I am your father' (length=16)
'self:: here means parent value' (length=30)
'static:: here means child value' (length=31)
'I am the child' (length=14)
'self:: here means child value' (length=29)
'static:: here means child value' (length=31)
'I am your father' (length=16)
'self:: here means parent value' (length=30)
'static:: here means parent value' (length=32)
abstract class Ghost {
protected static $var = 'I\'m a ghost';
final public static function __callStatic($method, $args = array()) {
echo self::$var;
}
}
class Person extends Ghost {
protected static $var = 'I\'m a person';
}
The call of Person::whatever() will print: I'm a ghost.
Why?
You're looking for something called Late Static Binding, which requires PHP 5.3+
"self" is used by Current class,
if you want get child static property, use "static" as :
final public static function __callStatic($method, $args = array()) {
echo **static**::$var;
}