范围解析操作符(::)

范围解析操作符(也可称作 Paamayim Nekudotayim)或者更简单地说是一对冒号,可以用于访问静态成员、方法和常量,还可以用于覆盖类中的成员和方法。

当在类的外部访问这些静态成员、方法和常量时,必须使用类的名字。

把 Paamayim Nekudotayim 选作该操作符的名字似乎有些奇怪。然而,这是 Zend 开发小组在写 Zend Engine 0.5 (被用于 PHP 3 中)时所作出的决定。事实上这个词在希伯莱文就是双冒号的意思。

例 19-12. 在类的外部使用 :: 操作符

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

echo
MyClass::CONST_VALUE;
?>

selfparent 这两个特殊的关键字是用于在类的内部对成员或方法进行访问的。

例 19-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";
    }
}

OtherClass::doubleColon();
?>

当一个子类覆盖其父类中的方法时,PHP 不会再执行父类中已被覆盖的方法,直到子类中调用这些方法为止。这种机制也作用于 构造函数和析构函数重载魔术 函数。

例 19-14. 调用父类的方法

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

class
OtherClass extends MyClass
{
    
// 覆盖父类中的方法
    
public function myFunc()
    {
        
// 但仍然可以调用已被覆盖的方法
        
parent::myFunc();
        echo
"OtherClass::myFunc()\n";
    }
}

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

add a note add a note User Contributed Notes
mongoose643 at gmail dot com
13-Feb-2007 08:11
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.<br>";
echo
"Before Setting: ".StaticSample::s_foo();
echo
"<br>";
echo
"While Setting: ".StaticSample::s_foo("VALUE HERE");
echo
"<br>";
echo
"After Setting: ".StaticSample::s_foo();
echo
"<br>";
echo
"While Removing: ".StaticSample::s_foo(null, 1);
echo
"<br>";
echo
"After Removing: ".StaticSample::s_foo();
echo
"<hr>";
echo
"Working with array values<br>";
$array = array(0=>"cat", 1=>"dog", 2=>"monkey");
echo
"Set an array value: ";
print_r(StaticSample::s_foo($array));
echo
"<br>";

//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
"<br>";

$changed_array = array(1=>"big dog", 3=>"bat", "bird"=>"flamingo");
echo
"Changing the value: ";
print_r(StaticSample::s_foo($changed_array));
echo
"<br>";

//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
"<br>";
echo
"Enjoy!";

?>
dexen at google dot me dot up
22-Sep-2006 02:40
``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 at mail dot ru
27-Jan-2006 11:57
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]
Kristof Coomans
25-Nov-2005 11:08
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)
zeldorblat at gmail dot com
07-Sep-2005 04:47
The alternative to john at johnjosephbachir dot org's suggestion without using eval():

call_user_func(array($classname, 'a_static_function'));
john at johnjosephbachir dot org
30-Aug-2005 10:23
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().
doug at douglassdavis dot com
29-Aug-2005 02:52
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
29-Apr-2005 12:58
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
thenewparadigm at hotmail dot com
05-Mar-2005 05:43
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.
ian at [first name]henderson dot org
01-Feb-2005 06:43
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.