On the php manual they define the scope resolution operator as following:
The Scope Resolution Operator (also called Paamayim Nekudotayim) or in simpler terms, the double colon, is a token that allows access to static, constant, and overridden properties or methods of a class.
My understanding is since we cannot assess static properties, class constants and static methods with $this, we need ::. I don't see why :: is allowed to assess non-static functions from inside the class. It could be said that a child class may want to assess the methods defined in the parent class with parent::baseClassMethod(), but then it might want to assess the properties defined in the parent class as well, but the :: can't assess the properties. It could be said that parent class's properties are inherited, so we can assess them simply with $this->prop, but the same is true with methods. We use :: for methods only when they are overriden in child class. Similarily we'd need :: to assess overriden properties in the child class. Contrary to the php manual definition, if you try to assess the overriden properties with ::, it throws error.
To illustrate my point, I have the following sample PHP code:
error_reporting(E_ALL);
class myClass {
private $prop = 786;
public $prop2 = 123;
public function changeType($var, $type){
settype($var, $type);
echo "function assessed through self";
}
public function display_prop(){
self::changeType(1, "string"); //why does this not throw error for non static function?
var_dump(self::$prop); //throws error; can't assess properties with self as expected.
}
}
class childCLass extends myClass {
public $prop2 = "new"; //overriden property.
public function display_prop(){ //overriden method.
echo "I do different things from the base class". "</br>";
}
public function dsiplay_overriden(){
echo parent::$prop2; //Why can't assess overriden properties, as suggested in the definition?
}
}
$obj = new myClass;
$obj->display_prop();
$obj2 = new childCLass;
$obj2->display_prop();
$obj2->dsiplay_overriden();
childClass::display_prop(); //This throws error as expected because non-static method.
To Sum it up I have two specific questions mainly:
Why can't we access overridden properties with :: as defined in the definition?
Why can we access non-static functions inside a class with ::, contrary to the definition?
P.S: A similar question has been asked on stackoverflow. No satisfactory answer exists, plus I am looking for a conceptual and insightful answer which is more appropriate at programmers.stackexchange.
I'll give it a try :)
Methods and static properties exist only once in memory, non-static properties of an class-instance (object) exist per instance, eg. have their own space in memory.
You cannot "override" a public or protected property of an class. Instead, the declaration of the same property-name in an derived class will "overshadow" the base class declaration. Effectively, they share the same place in memory, making them "the same", just as if you declare a variable of the same name twice in the global namespace. Reason for this is the inheritance, you inherit all public and protected properties of a base class.
Private properties are not inherited, an instance of a derived class will have 2 separate memory areas for a property of the same name. See Example A below.
Scope resolution does not prohibit the non-static access. The first sentence in PHP documentation even says so: The Scope Resolution Operator (also called Paamayim Nekudotayim) or in simpler terms, the double colon, is a token that allows access to static, constant, and overridden properties or methods of a class.
In fact, it resolves the scope, eg. it determines, if it has to access static (shared) or local memory.
The special variable $this can only access the local memory, it stands for the "reference to the current instance" and is automatically available in non-static class methods, but NOT in static methods! Historically it comes from C++ (keyword "this"), where class methods are organized in a map of function-pointers for all the class methods, so-called v-table. All non-static class methods receive an additional (invisible) last parameter named "this" and a call to non-static methods is resolved at runtime (in contrast to static methods which are resolved at compile time).
Now, when you create an instance of a class, like $obj = new Foo(); two things will happen - memory is allocated for the object and the constructor of the class is being called. Constructors cannot be declared static, simply because they are responsible to initialize the memory properly. As non-static method, they'll receive $this automatically.
So, when a non-static method is called, like $obj->method(), the runtime environment will recognize, the $obj is an class instance. It checks the v-table of the class to find the method (which is nothing else than a regular function, but with the extra parameter $this) and calls it, passing $obj as $this, pseudo code $vtable['Foo']['method']($obj). Inside the class method, you have then access to $this.
Lastly, calling a non-static method statically, respectively calling a static method in non-static fashion:
Actually you could do both, if you keep following in mind.
Non-static method, called with Foo::bar();: $this will be null!
Static method, called with $obj->bar();: Cannot reference $this in the method, as it won't be passed automatically!
Example A (Inheritance of public, protected and private members & static/non-static method access):
class A {
public $x = 'a_x';
protected $y = 'a_y';
private $z = 'a_z';
}
class B extends A {
public $x = 'b_x';
protected $y = 'b_y';
private $z = 'b_z';
public static function foo() {
echo 'foo' . PHP_EOL;
}
public function bar() {
echo 'bar' . PHP_EOL;
}
}
$a = new A();
$b = new B();
var_dump($a, $b);
$b->foo();
B::bar();
Output:
object(A)#1 (3) {
["x"]=>
string(3) "a_x"
["y":protected]=>
string(3) "a_y"
["z":"A":private]=>
string(3) "a_z"
}
object(B)#2 (4) {
["x"]=>
string(3) "b_x"
["y":protected]=>
string(3) "b_y"
["z":"B":private]=>
string(3) "b_z"
["z":"A":private]=>
string(3) "a_z"
}
foo
bar
As you can see, there is no problem calling a static function with $this->foo() nor a problem calling a non-static function with B::bar(). However, if you try to access $this in these scenarios, you'll get Fatal errors...
Related
Php manual for the late static bindings states, in the example of static usage in non-static context, that foo() will be copied to B? Is method inheritance copying with scope of the original function being maintained?
<?php
class A {
private function foo() {
echo "success!\n";
}
public function test() {
$this->foo();
static::foo();
}
}
class B extends A {
/* foo() will be copied to B, hence its scope will still be A and
* the call be successful */
}
class C extends A {
private function foo() {
/* original method is replaced; the scope of the new one is C */
}
}
$b = new B();
$b->test();
$c = new C();
$c->test(); //fails
As far as I can say, this is a problem of scope. When a child class does not override a parent's class method and you call said method via the child class, you will be in the parent class's scope and have access to private methods of the parent class.
If you implement a test() method in the child class, you will have that scope when you call it and will not be able to access private methods of the parent class.
I would say that 'copy' is not a fitting term for what's happening because the parent methods are not copied, they are just available in the child class, given the right scope. That is, they don't take the scope of the child class, but keep their own. They are only accessible in the child class if set to protected (or public) or if you call private methods with the parent's scope (as described in your example).
More information from your linke here: Strange behavior when overriding private methods
The official documentation does not explain it explicitly, but I could find this:
Private methods of a parent class are not accessible to a child class. As a result, child classes may reimplement a private method themselves without regard for normal inheritance rules.
http://codepad.viper-7.com/I0Zqoi
I don't understand what's wrong with this or how to fix it or why. Can someone who knows a little about programming please explain what's happening behind the scenes, like on the interpreter level? Also, how can I fix my problem, and why do I need to write my code in the way of the correction? Can you tell me, in human language, what is wrong with this and how to make it better? I guess my book isn't explaining well, and the code inside of it doesn't work. :/ Thank you.
class A
{
private $foo = 'bar';
function read()
{
echo self::$foo;
}
}
$a = new A();
a::read();
Strict Standards: Non-static method A::read() should not be called statically in /code/I0Zqoi on line 13
Fatal error: Access to undeclared static property: A::$foo in /code/I0Zqoi on line 8
The only workaround seems to be to add "static" in front of the method. Apparently, non-static methods cannot be accessed by static means (e.g., class A{function read(){echo "whatever"};} cannot be accessed by a::read() because the -> operator is necessary). Also, static properties cannot be accessed by object code, even if they exist within a function (e.g., class A{static $variable; function read(){echo $this->variable};} a->read(); won't work because the -> operator is being used to access a function that calls a static property.). By changing both the method and the property to static, the method can be accessed by static means. By changing both the method and property to non-static makes it so that either can be accessed with object instanciation. It doesn't make sense to me that the debugger is throwing errors because my book says that static properties can be called from non-static methods via object code calls to the non-static methods. So, is the debugger broken? Because I've tried every combination, and the code only seems to work if both the method and property are either static or non-static. :(((
The Strict Standards part is because a::read() is being called in a static context with ::. After declaring $a as a class instance of A, you should call the read() method on the variable using the -> operator:
// Proper non-static method call
$a = new A();
$a->read();
In the class definition, $foo is declared as a private property, but without the static keyword. It is then referred to in static context using the :: operator instead of the ->. The proper way to access it would beL
// Proper reference to non-static $foo
function read() {
echo $this->foo;
}
Now what does static mean anyway? Static methods and properties refer to class methods and properties that are shared by all current and future class instances. If A::$foo had been declared as:
private static $foo;
then there would be only the one $foo for all of class A in your code. Changing $foo would affect all instances of class A, and $foo can be accessed without even creating an instance of the class (like new A();)
Likewise, static methods can be called without creating an instance of the class because they do not modify class properties that are not also static.
// Static method call:
A::read();
To declare properties and methods as static, just add the static keyword:
// Property
private static $foo;
// Method
public static function foo() {}
EDIT for more examples:
class A
{
// Private property (non-static)
private $foo;
// Public property (static)
public static $bar = 12345;
// Public (non-static) function to access private $foo
public function getFoo() { return $this->foo; }
// Public (non-static) function to set private $foo
public function setFoo($newfoo) { $this->foo = $newfoo; }
// Static function
public static function incrementBar() { self::$bar++; }
}
Now see it in action:
// We haven't created any class instances yet (with the 'new' operator)
// But we can access the static properties & functions:
echo A::$bar . " ";
// prints 12345
A::incrementBar();
echo A::$bar . "\n";
// prints 12346
// Now we'll start working with class instances.
// Create 2 instances of class A
$a = new A();
$a->setFoo(8888);
$b = new A();
$b->setFoo(9999);
// It's a violation of strict standards to call getFoo() statically
// And it's meaningless to do so, because $foo only exists inside a class instance!
// Can't do this... Issues a strict warning since we're calling non-static getFoo() statically
//echo A::getFoo();
// But we can call getFoo() on the class instances:
echo $a->getFoo() . " " . $b->getFoo() . "\n";
// Prints 8888 9999
// Remember $bar was 12346...
echo $a::$bar . " " . $b::$bar . "\n";
// Prints 12346 12346
// Now modify the static property $bar again
// This affects all class instances.
A::incrementBar();
echo $a::$bar . " " . $b::$bar . "\n";
// Prints 12347 12347
I stuffed this whole thing into the codepad as well: http://codepad.viper-7.com/tV6omK
The book you're reading must not be paying attention to strict standards. If a non-static function does not attempt to access/modify a non-static property, you can call it statically successfully, but it WILL issue a strict warning. If the non-static function does modify or access a non-static property with $this->property, it will be a fatal error. You can't do that.
In PHP's error_reporting, the setting of E_ALL for show all errors actually does not include strict warnings. That has to be done with E_ALL & E_STRICT.
:: is used to access a static attribute. If you want to access an object attribute then use ->.
$a->read();
...
echo $this->$foo;
Although the other answers are definitely correct, here's an answer to your concrete question:
It doesn't make sense to me that the debugger is throwing errors because my book says that static properties can be called from non-static methods via object code calls to the non-static methods. So, is the debugger broken? Because I've tried every combination, and the code only seems to work if both the method and property are either static or non-static. :(((
The author of your book was under the impression that not getting an error message is considered clean code. It's not. You shouldn't have a method that can be called both statically as well as dynamically, as the two simply differ too much. Dynamic calls are for objects, where static calls are for classes. If you have the opportunity, I would always try to go the dynamic way, as that yields less coupling in the application.
As to why "the debugger is throwing errors" (it's the interpreter throwing E_STRICT warnings, but hey ;)): this behaviour has been changed in PHP five dot something. In PHP 4 you could call every method statically, even if it was a dynamic method. Possibly, your book is running behind on the facts.
i would like to know the difference between this two methods for initializing the object of a class
Method 1 (Using Scope resolution operator) :
Test::foo();
Method 2 (creating an instance of an object):
$test = new Test;
$test->foo();
also what is this -> operator called?
Test::foo() is merely statically calling a method of a class, it doesn't do anything with objects. It might initialize static values in the class, but you don't usually use static initializers. A static initializer may be used internally in the case of Singletons, but you should never call a public static initializer like this.
$test = new Test is actually instantiating an object, in which process it is likely initialized.
Please note the difference between initialize (setting up the initial state of an object/class/variable) and instantiate (create an object instance from a class).
-> is the T_OBJECT_OPERATOR.
:: is called "Paamayim Nekudotayim" (it's hebrew), -> is the object operator:
http://www.php.net/manual/en/language.oop5.paamayim-nekudotayim.php
Neither should be used to initialize your class. There's a magic __construct() method for that, which is called automatically by the new operator:
http://php.net/manual/en/language.oop5.decon.php
Test::foo() means call method foo() statically, outside of the scope of an actual object. Think of it as some kind of (slow) namespaced function.
$test->foo() means call method foo() for object $test.
http://www.php.net/manual/en/language.oop5.static.php
You need lear oop (Object Oriented Programming), and this implementation on PHP
The functions inside of classes, are called methods, this methods can be called on an instance of the class, or in static mode, The first call, don't create an instance of class*, this called the method 'foo' static.
class Test {
public static $static_atribute;
public $normal_atribute;
public function Foo($q) {
$this->normal_atribute = $q;
}
public static function SFoo ($q) {
// I dont can access to $this
self::$static_atribute = $q;
}
}
Test::Foo("hello");
// This thrown an error because $this dont exist in static mode
Test::SFoo("hello");
//This works, and the static property change
echo Test::$static_atribute;
// this puts "hello"
echo Test::$normal_atribute;
// this thrown an error
$a = new Test();
// $a is an instance of Test
$a->foo("hello");
// this works and the normal_atribute change in THIS instance
$b = new Test();
// $b is anoter instance of Test
$b->foo("bye");
// normal_atribute change in THIS instance
echo $a->normal_atribute;
// puts hello
echo $b->normal_atribute;
// puts bye
There is a pattern in which sused. called Singleton Pattern
I call it an arrow... but the difference is that with the arrow method, you're creating a new instance of that class as an object, which can then be referenced as an object. The other one simply calls a certain method of a certain class. With the object, you can store properties and call functions and store things in that object, and you can call multiple instances of that object and use them all separately... I'm rambling but there are tons of things you can do with an object that are limited with only calling the individual method.
I have seen function called from php classes with :: or ->.
eg:
$classinstance::function
or
$classinstance->function
whats the difference?
:: is used for scope resolution, accessing (typically) static methods, variables, or constants, whereas -> is used for invoking object methods or accessing object properties on a particular object instance.
In other words, the typical syntax is...
ClassName::MemberName
versus...
$Instance->MemberName
In the rare cases where you see $variable::MemberName, what's actually going on there is that the contents of $variable are treated as a class name, so $var='Foo'; $var::Bar is equivalent to Foo::Bar.
http://www.php.net/manual/en/language.oop5.basic.php
http://www.php.net/manual/language.oop5.paamayim-nekudotayim.php
The :: syntax means that you are calling a static method. Whereas the -> is non-static.
MyClass{
public function myFun(){
}
public static function myStaticFun(){
}
}
$obj = new MyClass();
// Notice how the two methods must be called using different syntax
$obj->myFun();
MyClass::myStaticFun();
Example:
class FooBar {
public function sayHi() { echo 'Hi!'; }
public /* --> */ static /* <-- */ function sayHallo() { echo 'Hallo!'; }
}
// object call (needs an instance, $foobar here)
$foobar = new FooBar;
$foobar->sayHi();
// static class call, no instance required
FooBar::sayHallo(); // notice I use the plain classname here, not $foobar!
// As of PHP 5.3 you can write:
$nameOfClass = 'FooBar'; // now I store the classname in a variable
$nameOfClass::sayHallo(); // and call it statically
$foobar::sayHallo(); // This will not work, because $foobar is an class *instance*, not a class *name*
::function is for static functions, and should actually be used as:
class::function() rather than $instance::function() as you suggest.
You can also use
class::function()
in a subclass to refer to parent's methods.
:: is normally used for calling static methods or Class Constants. (in other words, you don't need to instantiate the object with new) in order to use the method. And -> is when you've already instantiated a object.
For example:
Validation::CompareValues($val1, $val2);
$validation = new Validation;
$validation->CompareValues($val1, $val2);
As a note, any method you try to use as static (or with ::) must have the static keyword used when defining it. Read the various PHP.net documentation pages I've linked to in this post.
With :: you can access constants, attributes or methods of a class; the variables and methods need to be declared as static, otherwise they do belong to an instance and not to the class.
And with -> you can access attributes or methods of an instance of a class.
I always see people in serious projects use :: everywhere, and -> only occasionally in local environment.
I only use -> myself and never end up in situations when I need a static value outside of a class. Am I a bad person?
As I understand, the only situation when -> won't work is when I try following:
class StaticDemo {
private static $static
}
$staticDemo = new StaticDemo( );
$staticDemo->static; // wrong
$staticDemo::static; // right
But am I missing out on some programming correctness when I don't call simple public methods by :: ?
Or is it just so that I can call a method without creating an instance?
The double colon is used when you don't instantiate a class
class StaticDemo {...};
StaticDemo::static
if you do instantiate, use -->
class StaticDemo {...};
$s = new StaticDemo();
$s->static;
This is explained further at http://php.net/manual/en/language.oop5.patterns.php
:: is for referencing static properties or methods of a class. -> is for referencing instance properties and methods. You aren't missing out on any programming correctness, and if you are a bad person then it isn't because of this. Which one you use depends on the purpose of your class and how its written. But also, PHP didn't have namespaces until very recently so many people encapsulated their code in static classes to emulate namespaces to avoid naming collisions. It is possible you are seeing code that does that.
You caused a strict standards warning in E_STRICT mode. You are a bad person.
<?php
error_reporting(E_ALL | E_STRICT);
header('Content-type: text/plain');
class Foo {
public $msg = "Hello, public.\n";
public static $msgStatic = "Hello, static.\n";
public function write() {
echo "Hello, write.\n";
}
public static function writeStatic() {
echo "Hello, writeStatic.\n";
}
}
//echo Foo::$msg; // Fatal error: Access to undeclared static property: Foo::$msg
echo Foo::$msgStatic;
echo Foo::write(); // Strict Standards: Non-static method Foo::write() should not be called statically
echo Foo::writeStatic();
echo "------------------------\n";
$f = new Foo;
echo $f->msg;
echo $f->msgStatic; // Strict Standards: Accessing static property Foo::$msgStatic as non static
// Notice: Undefined property: Foo::$msgStatic
echo $f->write();
echo $f->writeStatic();
Output:
Hello, static.
Strict Standards: Non-static method Foo::write() should not be called statically in /home/adam/public_html/2010/05/10/bad.php on line 22
Hello, write.
Hello, writeStatic.
------------------------
Hello, public.
Strict Standards: Accessing static property Foo::$msgStatic as non static in /home/adam/public_html/2010/05/10/bad.php on line 29
Notice: Undefined property: Foo::$msgStatic in /home/adam/public_html/2010/05/10/bad.php on line 29
Hello, write.
Hello, writeStatic.
-> is for an instanciated class.
:: is a static call.
:: is used in inheritance constructors (a child accessing a parent constructor) and when referring to a static method inside another method.
I wouldn't say not using static calls makes you a bad person either!
Yes, you can call a method or access a value without creating an instance.
It would be useful, for example, if you have a value that all instances of a class use. Say this value, however, needs to be initialized at the beginning of your app. You could use something like StaticDemo::static = 42; to initialize it, and then all instances of your class would be able to access it.
As I understand it the static is shared between objects of the same type:
class test{
static function print_test(){
print "hello!";
}
}
$objectA = new test();
$objectB = new test();
The function print_test will be "shared" between the two objects. But the catch is the function print_test() should not reference anything inside the class! even thou PHP 5 accepts it.
Since the function print_test in the example just prints out "hello!" and doesn't reference anything inside the class why allocate memory for it in $objectA and $objectB? Just make one static function and $objectA and $objectB should point to it automatically.
Well that's the theory behind it in other languages, but since php5 allows you to reference $this in a static function I don't believe its a true static function since it would have to be dynamic to get any properties for ($this->variable) that unique object.
:: is used for static methods, which you call if you have no object instance.
Use "->" when in object context and "::" when accessing the class directly. In your example that would be:
class StaticDemo {
public static $staticVar = 'blabla';
public $normalVar = 'foobar';
}
$foo = new StaticDemo();
echo $foo->normalVar; //object context, echoes "foobar"
echo StaticDemo::staticVar; //class or "static" context, echoes "blabla"
Read this for detailed intel.
Or is it just so that I can call a method without creating an instance?
Correct.
The :: (scope resolution operators) are used when calling static methods/members. You don't have to create an instance to do this (like you did in your example).
Using -> and :: in the right context is the key to object-orientated programming correctness. You should only create static variables/methods when they apply to the class as a whole, and not only to a specific instance (object) of the class.
Static methods and properties are independent of a particular instantiation of a class. These must be accessed using double colons (::). Non-static methods and properties should be accessed using ->
This allows you do to some pretty cool things. A trivial example is a counter that keeps track of the number of instances of the class exists:
class foo {
public static $i = 0;
public function __construct() {
self::$i++;
}
}
$a = new foo();
$b = new foo();
echo foo::$i;
// outputs 2
As others have said,
:: 'double colon' is for referencing a static property or method.
-> 'dash arrow' is for referencing a property or method of a class instance.
But also its worth noting that
:: is often used in texts as shorthand to refer to a property or method that belongs to a certain class (whether it's static or instance).
See the 'Note...in documentation...' : http://books.google.co.uk/books?id=qVLjFk_4zVYC&lpg=PA66&dq=php%205%20objects&pg=PA46#v=onepage&q=php%205%20objects&f=false
Well you're right about how to use -> and ::. But sometimes it just doesn't make much sense to create objects of a class. Here's an example
Compare
class Settings
{
public static $setting1;
public static $setting2;
... // lots of other vars and functions
}
if(Setting::$setting1)
//do something
vs
class Settings
{
public $setting1;
public $setting2;
... // lots of other vars and functions
}
$set = new Settings()
if($set->setting1)
//do something
As I said It doesn't make sense to create instances as there's always only required one. in this case static fits better. It turns out in web we mostly deal with this kind of case unless you're dealing with real Objects e.g. users etc hence the prevalence of the former