Protected static member variables - php

I've recently been working on some class files and I've noticed that the member variables had been set in a protected static mode like protected static $_someVar and accessed like static::$_someVar.
I understand the concept of visibility and that having something set as protected static will ensure the member variable can only be accessed in the super class or derived classes but can I access protected static variables only in static methods?
Thanks

If I understand correctly, what you are referring to is called late-static bindings. If you have this:
class A {
protected static $_foo = 'bar';
protected static function test() {
echo self::$_foo;
}
}
class B extends A {
protected static $_foo = 'baz';
}
B::test(); // outputs 'bar'
If you change the self bit to:
echo static::$_foo;
Then do:
B::test(); // outputs 'baz'
Because self refers to the class where $_foo was defined (A), while static references the class that called it at runtime (B).
And of course, yes you can access static protected members outside a static method (i.e.: object context), although visibility and scope still matters.

Static variables exist on the class, rather than on instances of the class. You can access them from non-static methods, invoking them something like:
self::$_someVar
The reason this works is that self is a reference to the current class, rather than to the current instance (like $this).
By way of demonstration:
<?
class A {
protected static $foo = "bar";
public function bar() {
echo self::$foo;
}
}
class B extends A { }
$a = new A();
$a->bar();
$b = new B();
$b->bar();
?>
Output is barbar. However, if you try to access it directly:
echo A::$foo;
Then PHP will properly complain at you for trying to access a protected member.

Related

PHP function `get_object_vars` doesn't get private vars from inherited method

In this example I supposed that function getVars called from data would be able to return private vars names of Bdue to $this is an instance of B.
Instead of it, $this->getVars() returns an empty array.
Isn't get_object_vars called been private variables visible?
Isn't getVars a method inherited to B and called as if it was declared in it?
How can I get private variable names from a method declared in
an abstract class?
Example:
abstract class A
{
public function getVars()
{
return get_object_vars($this);
}
}
class B extends A
{
private $a;
private $b;
private $c;
public function data()
{
...
foreach($this->getVars() as $var) {
...
}
}
}
Private properties are only available to that class's methods. Try using protected properties to ensure the inherited methods have access to them.
The visibility of a property or method can be defined by prefixing the declaration with the keywords public, protected or private. Class members declared public can be accessed everywhere. Members declared protected can be accessed only within the class itself and by inherited classes. Members declared as private may only be accessed by the class that defines the member.
http://php.net/manual/en/language.oop5.visibility.php
Yes because get_object_vars is scope sensitive. If you don't wish to change the visibility of the variables then call get_object_vars directly from function data().
If you want to keep the code inheritance as it is, you'll have to change the visibility of the variables to protected.
abstract class A
{
public function getVars()
{
return get_object_vars($this);
}
}
class B extends A
{
protected $a;
protected $b;
protected $c;
public function data()
{
return $this->getVars();
}
}
$a = new B();
print_r($a->data());

Trying to understand PHP OOP

I'm wondering why the following code won't print out anything. I'm trying to access Bar::$some_var from method in parent class. Where Bar::$some_var is defined in it's constructor.
I've tried using self::$some_var and static::$some_var in Foo::hello() but neither worked. Do I have to make $some_var static?
class Foo {
private $some_var;
public function __construct() {
$this->some_var = 5;
}
public function hello() {
print $this->some_var;
}
}
class Bar extends Foo {
public function __construct() {
$this->some_var = 10;
}
}
$bar = new Bar();
$bar->hello();
Thanks in advance.
private makes a member variable unavailable outside of a class. You need to use protected to allow extending classes to have access to that variable.
protected $some_var;
See Visibility
Your class variable cannot be private if you would like your child class to access it.
Try protected instead and it should work!
:: operator is used to access class items (constants, static
variables, static methods)
-> operator is used to access object items (non static properties and methods)
anyway in your code the problem is visibility of $some_var. It has to be almost protected, public will also work

PHP: Limiting static property scope to specific class

abstract class Mother {
protected static $foo = null;
protected static $bar = null;
public function getFoo() { return static::$foo; }
public function getBar() { return static::$bar; }
public function setFoo($foo) { static::$foo = $foo; }
public function setBar($bar) { static::$bar = $bar; }
}
class Brother extends Mother {
protected static $foo = 'BROTHERS';
}
class Sister extends Mother {
protected static $foo = 'SISTERS';
}
$brother1 = new Brother();
$brother2 = new Brother();
$sister1 = new Sister();
$sister2 = new Sister();
$sister1->setBar('ONLY SISTERS'); // We set $bar = 'ONLY SISTERS' at sister1.
// We want only Sister instances to get this value...
// however Brother instances also get this value!
echo '<p>Brother 1: Foo="'.$brother1->getFoo().'", Bar="'.$brother1->getBar().'"</p>';
// Foo="BROTHERS", Bar="ONLY SISTERS"
echo '<p>Brother 2: Foo="'.$brother2->getFoo().'", Bar="'.$brother2->getBar().'"</p>';
// Foo="BROTHERS", Bar="ONLY SISTERS"
echo '<p>Sister 1: Foo="'.$sister1->getFoo().'", Bar="'.$sister1->getBar().'"</p>';
// Foo="SISTERS", Bar="ONLY SISTERS"
echo '<p>Sister 2: Foo="'.$sister2->getFoo().'", Bar="'.$sister2->getBar().'"</p>';
// Foo="SISTERS", Bar="ONLY SISTERS"
So apparently if static::$bar is not explicitly redefined in every child (Brother, Sister) their parent (Mother) will set the value for them (or at least for those who did not redefine it).
The question: Is there any way to prevent children who did not redefine static::$bar from receiving the new value? In other words, how to make sure only the referred class gets a new value, EVEN if static::$bar is not explicitly redefined in every child?
No, not the way you're doing it. That's what private scope is for. Child classes inherit all public and protected static properties--which mean they all point to the same value whether they are a parent, child, or sibling.
This is correct and good OO.
You should define the variable it as private static in the parent class and then the child wouldn't be able to see it directly and could create their own private static variable with the same name if needed.
Provide static getters and setters in your class to access the private static property.
Brother::getFoo();
Sister::getFoo();
You can make the getFoo() in the parent class Mother abstract or not, if you need to access it directly make it non-abstract so you can do:
Mother::getFoo();
This is just madness.
You should understand that extend defines IS A relationship. For example : class Duck extends Bird{} this means that every instance of Duck is a Bird.
So in your example, every Brother is a Mother. I fail to see how this would make a sense.
And the other thing : why the hell are you abusing static variables? What you are doing there is not object oriented programming. You are just wrapping global scope variables and functions in a namespace ( which happens to look like class ).
Some additional links on the subject, you might find useful:
static considered harmful
performance of static methods vs functions
clean code talks: global state and singletons
drawbacks of statuc methonds in php

php object oriented visibility

I'm a little confused about this paragraph on OO visibilty in PHP. was curious if someone could explain it to me. examples would be GREAT! my brain is not thinking clear.
http://www.php.net/manual/en/language.oop5.visibility.php
The first paragraph reads
The visibility of a property or method
can be defined by prefixing the
declaration with the keywords public,
protected or private. Class members
declared public can be accessed
everywhere. Members declared protected
can be accessed only within the class
itself and by inherited and parent
classes. Members declared as private
may only be accessed by the class that
defines the member.
how can a parent class access a childs class member?
That's how:
class A {
public function test() {
$b = new B;
echo $b->foo;
}
}
class B extends A {
protected $foo = 'bar';
}
$a = new A;
$a->test();
PHP is an interpreted language. Properties are resolved at runtime, not at the compiling stage. And access modifiers are just checked when a property is accessed.
It makes no difference if you ad-hoc inject a new (undeclared) property so it becomes public, or if you declare a protected property in an inherited class.
The private really only affects the accessibility from the outside. The ->name resolving at runtime works regardless of that. And the PHP runtime simply doesn't prope if the property declaration was made for the current object instances class. (Unlike for private declarations.)
public scope: property (method, variable etc) can be accessed from any class in any file.
class Example {
public $foo;
}
$example = new Example;
$example->foo = 3; // everything OK
private scope: property can only be accessed only by same class.
class Example {
private $foo;
}
class Child_Class extends Example {
public function some_method()
{
parent::foo = 3; // raises error
}
}
protected scope: property can only be accessed by same class or by other classes that extend it.
class Example {
protected $foo;
}
class Child_Class extends Example {
public function some_method()
{
parent::foo = 3; // this is OK
}
}
It all has to do with a technique named encapsulation, in which you must not allow a class member's state or behavior to be changed outside the class. http://en.wikipedia.org/wiki/Encapsulation_(object-oriented_programming)
Protected is a type of visibility which makes properties and methods declared protected available in the child classes of the declared class.
class Parent {
public $name = 'MyName';
protected $age = 20;
private $school = 'MySchool';
}
class Child extends Parent {
public function __construct() {
echo $this -> name; // valid as public
echo $this -> age; // valid as protected
echo $this -> school; // invalid as private
}
}
There you understand protected is something that used in inheritance.

declare property as object?

How do you declare a class property as an object?
I tried:
public $objectname = new $Object();
But it didn't work. Additionally, why should you do it like that?
Isn't it better to just instantiate that object and just use its members?
From the PHP manual on class properties (emphasis mine):
Class member variables are called "properties". You may also see them referred to using other terms such as "attributes" or "fields", but for the purposes of this reference we will use "properties". They are defined by using one of the keywords public, protected, or private, followed by a normal variable declaration. This declaration may include an initialization, but this initialization must be a constant value --that is, it must be able to be evaluated at compile time and must not depend on run-time information in order to be evaluated.
Either create it inside the constructor (composition)
class Foo
{
protected $bar;
public function __construct()
{
$this->bar = new Bar;
}
}
or inject it in the constructor (aggregation)
class Foo
{
protected $bar;
public function __construct(Bar $bar)
{
$this->bar = $bar;
}
}
or use setter injection.
class Foo
{
protected $bar;
public function setBar(Bar $bar)
{
$this->bar = $bar
}
}
You want to favor aggregation over composition.
If you are just looking to instantiate to a generic class you can do:
$objectname = new stdClass;
I don't believe you can do this in the declaration of a property so you'd have to just declare $objectname and in the constructor set it to new stdClass.
You can create a new class in constructer area then set it as new object.
class CampaignGroupsProperty
{
public $id;
public $name;
}
class GetCampaignGroupsResponse
{
public $result;
public $resultCode;
public $campaignGroups;
public function __construct()
{
$this->campaignGroups = new CampaignGroupsProperty();
}
}
Then you can call it like
$response = new GetCampaignGroupsResponse();
$response->campaignGroups->id = 'whatever';
$response->result=true;
PHP doesn't support explicit typing of class members. So you can't say:
public Object $objectname;
If the class Object exists, and you want an instance of it, try:
public $objectname = new Object();

Categories