From PHP mannual second paragraph, it says that:
static:: introduces its scope.
I tried the following example accordingly:
class Father {
public function test(){
echo static::$a;
}
}
class Son extends Father{
protected static $a='static forward scope';
public function test(){
parent::test();
}
}
$son = new Son();
$son->test(); // print "static forward scope"
It works as described. However, the following example will raise a fatal error:
class Father {
public function test(){
echo static::$a;
}
}
class Son extends Father{
private static $a='static forward scope';
public function test(){
parent::test();
}
}
// print "Fatal erro: Cannot access private property Son::$a"
$son = new Son();
$son->test();
My main question is how to interpret the word scope here? If static introduces Son's scope to Father, then why private variables are still invisible to Father?
Are there two things variable scope and visibility scope? I'm new to PHP sorry if this sounds funny.
There are two things at play here: scope and visibility. Both together decide if you can access the property.
As you found in your first test, late static binding lets $a be available in the scope of the Father class. That simply means the variable (not necessarily its value) is "known" to this class.
Visibility decides whether the variables in scope can be accessed by particular classes and instances. A private property is only visible to the class in which it is defined. In your second example, $a is defined private within Son. Whether or not any other class is aware it exists, it can not be accessed outside of Son.
static makes $a a property which is known to Father, but the property's visibility decides whether or not its value can be accessed.
As a test to further help understand it, try using self instead of static. You'll get back a different error that $a is not a property of Father.
Related
I am learning php and there are still alot of unclear areas for me in the language. I wonder when and why would we use private static properties inside the class. From what I understood private properties may only be accessed by the class where it was defined. So, the private part is clear, but the static is still unclear. In the docs it says:
Declaring class properties or methods as static makes them accessible
without needing an instantiation of the class. A property declared as
static cannot be accessed with an instantiated class object (though a
static method can).
Does that mean that I can access static properties without instantiation of the class. So, for example:
class Foo{
static $bar;
public function __construct($bar){
$this->bar = $bar;
}
So, I can access the $bar property of the class like so?
Foo::$bar
But, if I do this, it wouldn't work?
$foo = new Foo();
$foo::$bar
And, then if do make a property private static for which reason would we do that, since I thought we make them static in order to access them outside of their class and making them private would make that impossible. I would be very grateful if someone could clear this up to me.
When you declare a normal property, there is a different value of that property for every instance you create of that class (each object you create with new Foo). For a static property, there is one copy of that variable for the whole class.
This is separate from the visibility of that variable - a public static property exists once per class, and can be accessed from everywhere; a private static property exists once per class, but can only be accessed from inside that class's definition.
As a simple example, you could have a counter that gave each instance of the class a unique number. You don't need code outside the class to see or change this counter, so you mark it private, but it needs to be shared amongst all instances, so you mark it static.
class Foo {
// Static counter; shared with every instance
private static $nextID=0;
// Normal instance property: each instance will have its own value
private $myID;
public function __construct() {
// Set the ID for this instance to the next ID
$this->myID = self::$nextID;
// Increment the shared counter
self::$nextID++;
}
}
Static context within a PHP class (but outside of a function) is context which exists statically, that is without the need for a backing instance of an object.
Example:
class A {
public $a = 1;
public static $b = 2;
public function instanceFunction() {
A::$a; //Wrong way
$this->a //Right way
A::$b; //Works
self::$b; // Also works
static::$b; // Also also works
}
public static function staticFunction() {
A::$a; //Does not work
$this->a //Error $this within static context
A::$b; //Works
self::$b; // Also works
static::$b; // Also also works
}
}
A::$a; // Error $a is not static so it needs an instance of an object
A::$b; // Works
$Aobject=new A();
$Aobject->a; //Works
$Aobject->b // Does not work
Using self means "refer to the class I've written this in" e.g. in this case it's always A. Using static means "refer to the class I've called this from" which applies if static inheritance is involved which PHP does manage to pull off.
I don't understand a concept of class in php. I could be wrong.
I looked at a WordPress plugin. The class was defined and the properties of class wasn't created only functions were created.
Consider this example
class a
{
public function show(){
echo "hello";
$this->something = "xyz" ;
// What is this? How can "something" can be used here;
// as it is not defined in the class?
}
}
Then an object of that class was created in another file.
$obj = new a();
$obj->anothersomething = "abc"; // is it possible?
Enlighten me please.
My question is: Can we assign a value to undeclared property of a class?
Default class visibility is public.
However, it is good practice to explicitly declare class method with it's visibility.
class Foo
{
public function a() {}
protected function b() {}
private function c() {}
}
As #SougataBose mentioned, I'd suggest you running through PHP OOP course
Edit:
When it comes to properties - yes. It is possible to create them dynamically. Again, as a good practice, it is recommended to declare all properties in class body.
In this case it's not a function, but a public class method. Normally you need to define it with public/protected/private keyword, but when skipped, it's just public by default. So then in another file you create an instance of this class and call the public method show() which can then use class instance properties direct. Or you can assign these properties from outside using $obj->anothersomething = "xxx", which is not a good practice. All the assignments should be done through setter methods like this $obj->setProperty($value);
I understand OOP. What I understand so far is that private and protected cannot be referenced from outside the class using $this->blah notation. If that is correct, how can the following code work?
<?php
class test {
protected $a = "b";
public static function oo(){
$instance = new static();
echo $instance->a;
}
}
test::oo();
Gives me an output of b! Now, how in Lord's name can that happen?
In PHP 5.3, a new feature called late static bindings was added – and this can help us get the polymorphic behavior that may be preferable in this situation. In simplest terms, late static bindings means that a call to a static function that is inherited will “bind” to the calling class at runtime. So, if we use late static binding it would mean that when we make a call to “test::oo();”, then the oo() function in the test class will be called.after that you return $instance->a; static keyword allows the function to bind to the calling class at runtime.so if you use static then whatever access modifier(private,public,protected) you use it's just meaning less...
please read this link,another
That happens because you're "presenting it" by echo'ing it. You can't reference it like this for example:
class test {
private $a = 'b';
function __construct() {
echo 'instantiated';
}
}
$test = new test();
echo $test->a; // This line won't work, since it's a private var.
It would give you an error message that looks like this:
Fatal error: Cannot access private property test::$a
Example (https://eval.in/226435)
As I said before, you're accessing it from within the class itself, so you CAN view it. (That's the $instance you have there.) If you modify your code to use it like this:
class test {
protected $a = "b";
public static function oo(){
$instance = new static();
return $instance;
}
}
echo test::oo()->a;
Example of the above (https://eval.in/226439)
You'll get that "private acess blah blah" error.
You're understanding the statement wrong. "private and protected cannot be referenced from outside the class" means that as the examples above show, you CAN NOT access the variables outside the class, but with your example, you're accessing it from INSIDE the class, which means they'll do as you require (echo'ing out as you did)
What I understand so far is that private and protected cannot be referenced from outside the class
As follows, since oo is defined in the same type as a, oo has access to a.
This is actually a very good question, and shouldn't be down-voted.
From what I understand, the reason why you can access a protected/private property from within a static method of the same class, is because "the implementation specific details are already known when inside this class". I rephrased this a little from what is documented on the official page on Visibility:
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.
This makes sense. Visibility access is meant to only expose things that are safe for the public to use. But if you already have access to the code of the Class you're using, then there is no point of preventing you to use what you already see. Hope that makes sense..
I am having trouble understanding how to work with objects.
The specific code:
class first{
class second{
public function widgets(){
$a_variable = $a_value;
}
#1
}
$second = new second;
#2
}
#3
$first = new first;
If I initialize $a_variable as $a_variable it is only available inside the function, correct?
If I initialize $a_varialbe as $this->a_variable it is only available inside class second, correct?
Can I initialize $a_variable as $first->second->a_variable? If so, How would I call it at #1, #2, and #3?
Can I initialize $a_varialbe as $this->second->a_variable? If so, How would I call it at #1, #2, and #3?
As you can see I am simply confused as to how OOP works.
First of all, I want to express how much I appreciate all of the help. I have already learned more than enough to consider this question a smashing success.
That said, even if it is poorly formulated, psuedo-code and invalid syntax, this code DOES run.
class class_1{
public function function_1(){
require('class_2.php');
public function function_2_callback(){
//%%%%%% How do I set a variable here and get the DATA...
}
$this->class_2 = new class_2("function_2_callback");
}
}
$class_1 = new class_1;
//&&&&&&&&&& Get the DATA here?
/* CONTENTS OF class_2.php */
class class_2($callback){
call_user_function($callback);
}
Even if we have to look at this as an exercise. Can someone tell me how I would first set (# %%%%%%%)and then call a variable (# &&&&&&&&) as shown?
First off: What you have there doesn't work, you cannot declare a class inside a class the way you are doing (notwithstanding conditionally declaring a class inside a function, which you should not do).
Scope in PHP (including OOP) is very simple:
variables have function scope
object properties are accessible if you have a reference to the object
the visibility of object properties can be restricted
The only real scope you have is function scope for variables:
$a = 'foo';
function bar() {
$a = 'bar';
}
The two $as are entirely unrelated, in different scopes. As simple as that.
class Foo {
public $a = 'foo';
public function bar() {
$this->a; // foo
$a = 'bar';
}
}
$foo = new Foo;
$foo->a; // foo
An object property has no scope, it has visibility. You can access it if you have the object in scope. Above, $foo is the object. It's in scope, its property a is public, therefore it can be accessed using $foo->a. Inside the class, the property is accessible via $this->a.
The $a = 'bar' is a local variable in the function and has nothing to do with $this->a. It is not accessible anywhere except inside the function. Refer to rule #1, function scope.
class Bar {
protected $b = 'bar';
public function baz() {
$this->b; // bar
}
}
$bar = new Bar;
$bar->b; // doesn't work
If the visibility is not public, the property (here b) is not accessible from outside the class itself. Inside the class you can access it using $this->b, but not from outside using $bar->b. It's not about scope, but visibility.
And that's pretty much the scope rules in PHP.
First of all your example is invalid code
PHP does not support nested classes, meaning a class within a class.
if you define a class, a variable initialized within a method is local to that method, while you can "initialize" an attribute with $this->newattribute, you should have declared it and its visibility before (before you write a method public / private / protected $varname = "initial value";).
Your questions 3 and 4 would make sense in another context, this is when an object is passed as member of another object, see example below.
If you build it like
<?php
class First {
public $second;
}
class Second {
public $a_variable;
}
$foo = new First();
$foo->second = new Second();
you can access it:
$foo->second->a_variable = "foo";
or within a method in second with
$this->a_variable;
or within a method in first with
$this->second->a_variable;
You should NOT be nesting classes like that. That shouldn't even run. I would suggest running the code first. There are some tools online for testing small snippets of PHP code, such as this.
For the code to run as you might expected it to, it should look like this:
class second{
public function widgets(){
$a_variable = $a_value;
}
}
class first{
public $second;
public function __construct() {
$this->second = new second;
}
}
$first = new first;
A variable that begins with $[a-z]+ is local to the function. A property beginning with $this->[a-z]+ (where [a-z] is 1 or more letters) is part of the object.
There's some documentation on php.net that goes over the specifics of objects in php here.
If I initialize $a_variable as $a_variable it is only available inside
the function, correct?
Yes, correct. It begins with $[a-z]. Not quite true if you use the global keyword, but that's discouraged.
If I initialize $a_varialbe as
$this->a_variable it is only available inside class second, correct?
Yes, but you should declare it first. You can do this with public $variable, protected $variable or private $variable. public means a property can be accesses from the outside, whereas private means only the class itself can access it. protected is private to the outside, but public to classes that extend from your class.
(public/private/public became available in PHP 5. In PHP 4 you would use var $variable, which defaults to public in PHP 5)
Can I initialize $a_variable as $first->second->a_variable?
You can arbitrarily initialize class variables without declaring them, but that's not something you should be doing.
If so, How would I call it at #1, #2, and #3?
You can't call code there (in your example). Code must be inside a function or in the global context (outside of the class definition).
A Brief Explanation of Classes
class foo{
// This can be accessed anywhere
public $i_am_public;
// This can be accessed within this class and any sub classes
protected $i_am_protected;
// Thi can only be accessed within this class
private $i_am_private;
// This function can be accessed anywhere
public function foo_function(){
// This variable is only available in this function
// it cannot be accessed anywhere else
$variable = 'Hello World';
// However, you can access any of the other variables listed above
// like so
$this->i_am_public = 'public';
$this->i_am_protected = 'protected';
$this->i_am_private = 'private';
// Write these variables
echo $this->i_am_public;
echo $this->i_am_protected;
echo $this->i_am_private;
}
}
$foo = new foo;
$foo->foo_function();
// You can change any publicly defined variables outside
// of the class instance like so
$foo->i_am_public = 'testing';
Specific Answers to Questions
Before I go any further, I would hugely urge you not to define a class within a class! Instead, use class extensions which I will explain later. In fact, I am surprised your code even works!
If I initialize $a_variable as $a_variable it is only available inside
the function, correct?
Yes, this will only be available inside the function. If you want to access it outside of the function then you need to define it outside the function using one of the scope definitions public, protected, private.
If I initialize $a_varialbe as $this->a_variable it is only available
inside class second, correct?
This depends on what scope you give it, but you shouldn't be defining a class within a class anyway.
Can I initialize $a_variable as $first->second->a_variable? If so, How
would I call it at #1, #2, and #3?
I cannot answer this as I have never nested a class within a class, once again I would urge you to change this structure.
Can I initialize $a_varialbe as $this->second->a_variable? If so, How
would I call it at #1, #2, and #3?
Please see above answer :-)
Nesting Classes
As mentioned, I have never seen this before, and I am surprised it even works. You should definitely change this structure.
One suggestions would be to use extensions like so:
class foo{
// This can be accessed anywhere
public $i_am_public;
// This can be accessed within this class and any sub classes
protected $i_am_protected;
// Thi can only be accessed within this class
private $i_am_private;
public function foo_function(){
echo 'Hello World';
}
}
class bar extends foo {
// This is a public function
public function baz(){
// These will work
$this->i_am_public = 'public';
$this->i_am_protected = 'protected';
// This will not work as it is only available to
// the parent class
$this->i_am_private = 'private';
}
}
// This will create a new instance of bar which is an
// extension of foo. All public variables and functions
// in both classes will work
$bar = new bar;
// This will work because it is public and it is inherited
// from the parent class
$bar->foo_function();
// This will work because it is public
$bar->baz();
I noticed two ways in PHP to do the same thing. Can you tell me which way is a better programming practice?
In the first example, I use a private variable on the class. On the second example, I use a static variable in a class method.
class Test {
private $_myvar;
public function getVar(){
if (!isset($this->_myvar)) {
$this->_myvar = "test\n";
}
return $this->_myvar;
}
}
$oTest = new Test();
echo $oTest->getVar(); // sets var first time and returns it
echo $oTest->getvar(); // pulls from cache
Or:
class Test {
public function getVar(){
static $myvar;
if (!isset($myvar)) {
$myvar = "test\n";
}
return $myvar;
}
}
$oTest = new Test();
echo $oTest->getVar(); // sets var first time and returns it
echo $oTest->getvar(); // pulls from cache
That is like saying which room is better the Kitchen or the Bathroom, they are both rooms, but they have different functions.
A static variable is the same in multiple objects.
An instance variable, declared via private above is particular to a given object.
Note that private is an access modifier, static is not, a variable can be both.
In the location you have your static variable, within the function, it is not a class/object variable at all, but a traditional function-level static variable, which will be single-instanced across all calls to the function, making it similar to a class-level static variable, but only accessible within the method it is defined within.
With the class property (be it public, private or protected), the variable is accessible to other parts of the class.
With the static variable, it is only visible to that method of the class.
I would suggest using the class property (but probably not private, which I generally don't find much use for; protected is normally a better idea) as it's easier for testing later; you can't do anything to unset, alter or check the static variable.
I see some possible confusion in the other answers here between static variables and static class properties. PHP uses the same modifier, but the behaviour is quite different; an example follows.
<?php
class Foo {
// Static class property
public static $bar = 'bar';
public function blarg() {
static $bar;
if (empty($bar)) {
$bar = 'blarg';
}
return $bar;
}
}
In the above example the static class property can be accessed using Foo::$bar (or self::$bar within the class and static::$bar in PHP 5.3); the static variable cannot and is only visible inside the function blarg().
Neither is "better". It would be like asking whether a screwdriver is better than a tenon saw.
The private variable in your first example will only be available to that instance of the class (although only to its methods). Create a new instance, and the variable can and will have a different value.
The static variable in your second example will be available to all instances of that class, admittedly only in that method. But set it one instance, and a second instance will see the same value.