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.
Related
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.
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();
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...
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.
What does static mean?
I know public means that it can be accessed from outside the class, and private only from inside the class…
Static means that it can be accessed without instantiating a class. This is good for constants.
Static methods need to have no effect on the state of the object. They can have local variables in addition to the parameters.
public: Public declared items can be accessed everywhere.
protected: Protected limits access to inherited and parent
classes (and to the class that defines the item).
private: Private limits visibility only to the class that defines
the item.
static: A static variable exists only in a local function scope,
but it does not lose its value when program execution leaves this scope.
final: Final keywords prevents child classes from overriding a
method by prefixing the definition with final. If the class itself is
being defined final then it cannot be extended.
Beside of PHP:
transient: A transient variable is a variable that may not
be serialized.
volatile: A variable that might be concurrently modified by multiple
threads should be declared volatile. Variables declared to be volatile
won't be optimized by the compiler because their value can change at
anytime.
From http://php.net/manual/en/language.oop5.static.php
Declaring class properties or methods
as static makes them accessible
without needing an instantiation of
the class. A property declared as
static can not be accessed with an
instantiated class object (though a
static method can).
An example: when use the static keyword, we cannot use $this
class Foo {
private $foo='private';
private function priv_func() {
echo 'priv_method';
}
public static function get() {
echo $this->foo;
$this->priv_func();
}
}
$obj = new Foo();
$obj->get();
Fatal error: Using $this when not in object context in (…)
Example:
public class Methods_Test1
{
public static void Display(String Name)
{
System.out.println("Hello There " + Name);
System.out.println("I am from Display method");
}
public static void main(String[] args)
{
Scanner sc = new Scanner(System.in);
System.out.println("Enter name");
String name = sc.next();
Obj.Display(name);
}
The public static void Display(String name) method accessible as static method within its own class which can be accessed without creating object of the class where as the same method behaves as public for the outside classes which can be accessed by creating object.