Delicious Bookmark this on Delicious Share on Facebook SlashdotSlashdot It! Digg! Digg



PHP : Language Reference : Classes and Objects (PHP 5) : Scope Resolution Operator (::)

Scope Resolution Operator (::)

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 members or methods of a class.

When referencing these items from outside the class definition, use the name of the class.

As of PHP 5.3.0, it's possible to reference the class using a variable. Keywords like self, parent or static are not allowed in dynamic class references.

Paamayim Nekudotayim would, at first, seem like a strange choice for naming a double-colon. However, while writing the Zend Engine 0.5 (which powers PHP 3), that's what the Zend team decided to call it. It actually does mean double-colon - in Hebrew!

Example 10.12. :: from outside the class definition

<?php
class MyClass {
   const
CONST_VALUE = 'A constant value';
}

$classname = 'MyClass';
echo
$classname::CONST_VALUE;

echo
MyClass::CONST_VALUE;
?>


Two special keywords self and parent are used to access members or methods from inside the class definition.

Example 10.13. :: from inside the class definition

<?php
class OtherClass extends MyClass
{
   public static
$my_static = 'static var';

   public static function
doubleColon() {
       echo
parent::CONST_VALUE . "\n";
       echo
self::$my_static . "\n";
   }
}

$classname = 'OtherClass';
echo
$classname::doubleColon();

OtherClass::doubleColon();
?>


When an extending class overrides the parents definition of a method, PHP will not call the parent's method. It's up to the extended class on whether or not the parent's method is called. This also applies to Constructors and Destructors, Overloading, and Magic method definitions.

Example 10.14. Calling a parent's method

<?php
class MyClass
{
   protected function
myFunc() {
       echo
"MyClass::myFunc()\n";
   }
}

class
OtherClass extends MyClass
{
   
// Override parent's definition
   
public function myFunc()
   {
       
// But still call the parent function
       
parent::myFunc();
       echo
"OtherClass::myFunc()\n";
   }
}

$class = new OtherClass();
$class->myFunc();
?>


Code Examples / Notes » language.oop5.paamayim_nekudotayim

dexen

``self'' and ``parent'' are valid arguments to the ``new'' operator. All the constructor stuff works as expected. Example:
<?php
class Foo {}
class Bar extends Foo {
static function test() {
return(
array(
new self,
new self(),
new parent( 'a', 1 ),
) );
}
}
print_r( Bar::test() ); ?>
Calling Bar::test() gives you nice list of three instances. ( i'm describing it there, as it was a suprise to me. ) Maybe you can find it usefull, for example, in some generic ::__clone() method that works across inheritance tree.


developit

You use 'self' to access this class, 'parent' - to access parent class, and what will you do to access a parent of the parent? Or to access the very root class of deep class hierarchy? The answer is to use classnames. That'll work just like 'parent'. Here's an example to explain what I mean. Following code
<?php
class A
{
   protected $x = 'A';
   public function f()
   {
       return '['.$this->x.']';
   }
}
class B extends A
{
   protected $x = 'B';
   public function f()
   {
       return '{'.$this->x.'}';
   }
}
class C extends B
{
   protected $x = 'C';
   public function f()
   {
       return '('.$this->x.')'.parent::f().B::f().A::f();
   }
}
$a = new A();
$b = new B();
$c = new C();
print $a->f().'<br/>';
print $b->f().'<br/>';
print $c->f().'<br/>';
?>
will output
[A] -- {B} -- (C){C}{C}[C]


mongoose643

This is a solution for those that still need to write code compatible with php 4 but would like to use the flexibility of static variables. PHP 4 does not support static variables within the class scope but it does support them within the scope of class methods. The following is a bit of a workaround to store data in static mode in php 4.
Note: This code also works in PHP 5.
(Tested on version 4.3.1+)
The tricky part is when using when arrays you have to do a bit of fancy coding to get or set individual elements in the array. The example code below should show you the basics of it though.
<?php
class StaticSample
{
//Copyright Michael White (www.crestidg.com) 2007
//You may use and modify this code but please keep this short copyright notice in tact.
//If you modify the code you may comment the changes you make and append your own copyright
//notice to mine. This code is not to be redistributed individually for sale but please use it as part
//of your projects and applications - free or non-free.


//Static workaround for php4 - even works with arrays - the trick is accessing the arrays.
//I used the format s_varname for my methods that employ this workaround. That keeps it
//similar to working with actual variables as much as possible.
//The s_ prefix immediately identifies it as a static variable workaround method while
//I'm looking thorugh my code.
function &s_foo($value=null, $remove=null)
{
static $s_var; //Declare the static variable. The name here doesn't matter - only the name of the method matters.

if($remove)
{
if(is_array($value))
{
if(is_array($s_var))
{
foreach($value as $key => $data)
{
unset($s_var[$key]);
}
}
}
else
{
//You can't just use unset() here because the static state of the variable will bring back the value next time you call the method.
$s_var = null;
unset($s_var);
}
//Make sure that you don't set the value over again.
$value = null;
}
if($value)
{
if(is_array($value))
{
if(is_array($s_var))
{
//$s_var = array_merge($s_var, $value); //Doesn't overwrite values. This adds them - a property of the array_merge() function.
foreach($value as $key => $data)
{
$s_var[$key] = $data; //Overwrites values.
}
}
else
{
$s_var = $value;
}
}
else
{
$s_var = $value;
}
}

return $s_var;
}
}
echo "Working with non-array values.
";
echo "Before Setting: ".StaticSample::s_foo();
echo "
";
echo "While Setting: ".StaticSample::s_foo("VALUE HERE");
echo "
";
echo "After Setting: ".StaticSample::s_foo();
echo "
";
echo "While Removing: ".StaticSample::s_foo(null, 1);
echo "
";
echo "After Removing: ".StaticSample::s_foo();
echo "<hr>";
echo "Working with array values
";
$array = array(0=>"cat", 1=>"dog", 2=>"monkey");
echo "Set an array value: ";
print_r(StaticSample::s_foo($array));
echo "
";
//Here you need to get all the values in the array then sort through or choose the one(s) you want.
$all_elements = StaticSample::s_foo();
$middle_element = $all_elements[1];
echo "The middle element: ".$middle_element;
echo "
";
$changed_array = array(1=>"big dog", 3=>"bat", "bird"=>"flamingo");
echo "Changing the value: ";
print_r(StaticSample::s_foo($changed_array));
echo "
";
//All you have to do here is create an array with the keys you want to erase in it.
//If you want to erase all keys then don't pass any array to the method.
$element_to_erase = array(3=>null);
echo "Erasing the fourth element: ";
$elements_left = StaticSample::s_foo($element_to_erase, 1);
print_r($elements_left);
echo "
";
echo "Enjoy!";
?>


anonymous

There's no surprize here. These resolution rules are identical in C++ and Java, where static fields (and methods) are not separately instanciated within the inheritance tree for the new derived classes.
This is per design. If you want per-class static fields,you have to overload each static field (or method) to assign them a new value that will hide the inherited static field (or method). The "$self::" scope in a static method does not refer to the object or class from which the method is called, as it is statically compiled and resolved within the class declaring the method.
In other words "$self::" is just needed to specify the field declared in the defining class, instead of a homonym variable (or function) in the local scope which may hide it. This is exactly similar to the "this." scope specifier (used with the "." operator here) used in C++ (or Java).
The same can be said about the semantic of "$super::" used within a static method (similar to "super." scope specifier used in C++ or Java).
Neither PHP, nor C++, have a way to work on instanciated class objects as if they were objects of the first grade (that's why C++ and Java are making distinctions between classes and interfaces).
On the opposite Javascript/ECMAScript defines classes like standard objects with a "prototype" field for the fields (or methods) to inherit instead of duplicating them with the new operator. When working in PHP, forget Javascript, think like in C++ and Java.


thenewparadigm

There is also a quirk with using the scope resolution operator on static class variables.  Below is an example using a highly modified version of Ian's code:
<?php
class ExampleSuperclass
{
  static $className;
  static function showClassName() {
     echo self::$className . "\n";
  }
}
class ExampleSubclassOne extends ExampleSuperclass
{
  static function setClassName()
  {
      self::$className = "subclassOne";
  }
}
class ExampleSubclassTwo extends ExampleSuperClass
{
  static function setClassName()
  {
     self::$className = "subclassTwo";
  }
}
// setting variables for each class
ExampleSubclassOne::setClassName();
ExampleSubclassTwo::setClassName();
ExampleSubclassOne::showClassName();  // output is "subclassTwo"!
// more output:
echo ExampleSubclassOne::$className . "\n"; // output is "subclassTwo"!
echo ExampleSubclassTwo::$className . "\n"; // output is "subclassTwo"
echo ExampleSuperclass::$className . "\n"; // output is "subclassTwo"!
?>
appearantly, any static variables defined in a superclass are directly referenced in subclasses,
and all changes are visible throughout the class heirarchy.  care must be taken when using static
class variables.


zeldorblat

The alternative to john at johnjosephbachir dot org's suggestion without using eval():
call_user_func(array($classname, 'a_static_function'));


ian

Please note that methods called by the scope resolution operator which are defined by a superclass of the first operand are called in the scope of the SUPERCLASS.  For example,
<?php
class ExampleSuperclass
{
static function classType()
{
return "superclass";
}
static function doSomething()
{
echo "doing something with " . self::classType();
}
}
class ExampleClass extends ExampleSuperclass
{
static function classType()
{
return "subclass";
}
}
ExampleClass::doSomething();
// output is "doing something with superclass"!
?>
This can be surprising (it surprised me!) when coming from other object-oriented languages, which would output "doing something with subclass" in this case.


doug

Just a note that while this works for new objects:
<?php
$obj = new $classname();
?>
and this works to call a function:
<?php
$functionname();
?>
this does not work to call static functions, you will get a parse error:
<?php
$classname::a_static_function();
?>


huugjeweg

In response to ian at [first name]henderson dot org:
You are not allowed to redefine static methods, see
http://www.php.net/manual/en/language.oop5.static.php
And in response to thenewparadigm at hotmail dot com: the behaviour you describe seems appropriate for *classes* with static variables, see "Using static variables" on http://nl2.php.net/static


kristof coomans

In response to ian at [first name]henderson dot org:
(related bogus bug report: http://bugs.php.net/bug.php?id=26930)
The functionality you've expected maybe will be possible in PHP6, probably by using the static keyword in conjunction with the scope resolution parameter. You can read more about this in the minutes of the PHP developers meeting at 11 and 12 november in Paris: http://www.php.net/~derick/meeting-notes.html point 5.4: Late static binding using "this" without "$" (or perhaps with a different name)


john

A way to achieve Doug's last example
<?php
//this doesn't work
$classname::a_static_function();
?>
is to use eval():
<?php
//this works
$string = $classname.'::a_static_function();';
eval($sting);
?>
Remember to include a semicolon inside the string passed to eval().


Change Language


Follow Navioo On Twitter
Introduction
The Basics
Autoloading Objects
Constructors and Destructors
Visibility
Scope Resolution Operator (::)
Static Keyword
Class Constants
Class Abstraction
Object Interfaces
Overloading
Object Iteration
Patterns
Magic Methods
Final Keyword
Object cloning
Comparing objects
Reflection
Type Hinting
Late Static Bindings
eXTReMe Tracker