文字

范围解析操作符(::)

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

当在类定义之外引用到这些项目时,要使用类名。

自 PHP 5.3.0 起,可以通过变量来引用类,该变量的值不能是关键字(如 selfparentstatic)。

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

Example #1 在类的外部使用 :: 操作符

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

$classname  'MyClass' ;
echo 
$classname :: CONST_VALUE // 自 PHP 5.3.0 起

echo  MyClass :: CONST_VALUE ;
?>

self parent static 这三个特殊的关键字是用于在类定义的内部对其属性或方法进行访问的。

Example #2 在类定义内部使用 ::

<?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 ();  // 自 PHP 5.3.0 起

OtherClass :: doubleColon ();
?>

当一个子类覆盖其父类中的方法时,PHP 不会调用父类中已被覆盖的方法。是否调用父类的方法取决于子类。这种机制也作用于构造函数和析构函数,重载以及魔术方法。

Example #3 调用父类的方法

<?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 ();
?>

参见 伪变量的示例。

用户评论:

[#1] jasverix at NOSPAM dot gmail dot com [2013-10-03 13:25:19]

Just found out that using the class name may also work to call similar function of anchestor class.

<?php

class Anchestor {
   
   public 
$Prefix '';

   private 
$_string =  'Bar';
    public function 
Foo() {
        return 
$this->Prefix.$this->_string;
    }
}

class 
MyParent extends Anchestor {
    public function 
Foo() {
         
$this->Prefix null;
        return 
parent::Foo().'Baz';
    }
}

class 
Child extends MyParent {
    public function 
Foo() {
        
$this->Prefix 'Foo';
        return 
Anchestor::Foo();
    }
}

$c = new Child();
echo 
$c->Foo(); //return FooBar, because Prefix, as in Anchestor::Foo()

?>


The Child class calls at Anchestor::Foo(), and therefore MyParent::Foo() is never run.

[#2] guy at syntheticwebapps dot com [2013-09-15 20:29:24]

It seems as though you can use more than the class name to reference the static variables, constants, and static functions of a class definition from outside that class using the :: . The language appears to allow you to use the object itself. 

For example:
class horse 
{
   static $props = {'order'=>'mammal'};
}
$animal = new horse();
echo $animal::$props['order'];

// yields 'mammal'

This does not appear to be documented but I see it as an important convenience in the language. I would like to see it documented and supported as valid. 

If it weren't supported officially, the alternative would seem to be messy, something like this:

$animalClass = get_class($animal);
echo $animalClass::$props['order'];

[#3] remy dot damour at ----no-spam---laposte dot net [2010-05-05 13:50:18]

As of php 5.3.0, you can use 'static' as scope value as in below example (add flexibility to inheritance mechanism compared to 'self' keyword...)

<?php

class {
    const 
'constA';
    public function 
m() {
        echo static::
C;
    }
}

class 
extends {
    const 
'constB';
}

$b = new B();
$b->m();

// output: constB
?>

[#4] Theriault [2009-12-05 20:58:15]

A class constant, class property (static), and class function (static) can all share the same name and be accessed using the double-colon.

<?php

class {

    public static 
$B '1'# Static class variable.

    
const '2'# Class constant.
    
    
public static function B() { # Static class function.
        
return '3';
    }
    
}

echo 
A::$B A::A::B(); # Outputs: 123
?>

[#5] wouter at interpotential dot com [2009-11-09 07:24:52]

It's worth noting, that the mentioned variable can also be an object instance. This appears to be the easiest way to refer to a static function as high in the inheritance hierarchy as possible, as seen from the instance. I've encountered some odd behavior while using static::something() inside a non-static method.

See the following example code:

<?php
class FooClass {
    public function 
testSelf() {
        return 
self::t();
    }

    public function 
testThis() {
        return 
$this::t();
    }

    public static function 
t() {
        return 
'FooClass';
    }

    function 
__toString() {
        return 
'FooClass';
    }
}

class 
BarClass extends FooClass {
    public static function 
t() {
        return 
'BarClass';
    }

}

$obj = new BarClass();
print_r(Array(
    
$obj->testSelf(), $obj->testThis(),
));
?>


which outputs:

<pre>
Array
(
    [0] => FooClass
    [1] => BarClass
)
</pre>

As you can see, __toString has no effect on any of this. Just in case you were wondering if perhaps this was the way it's done.

[#6] giovanni at gargani dot it [2009-06-02 06:38:46]

Well, a "swiss knife" couple of code lines to call parent method. The only limit is you can't use it with "by reference" parameters.
Main advantage you dont need to know the "actual" signature of your super class, you just need to know which arguments do you need

<?php
class someclass extends some superclass {
// usable for constructors
 
function __construct($ineedthisone) {
  
$args=func_get_args(); 
  

  
call_user_func_array(array('parent',__FUNCTION__),$args);
 }
// but this is not for __construct only
 
function anyMethod() {
  
$args=func_get_args();
  
call_user_func_array(array('parent',__FUNCTION__),$args);
 }
  
// Note: php 5.3.0 will even let you do
 
function anyMethod() {
  
//Needs php >=5.3.x
  
call_user_func_array(array('parent',__FUNCTION__),func_get_args());
 }

}
?>

[#7] erwinhaantjes at interurbia dot nl [2009-04-11 14:36:39]

Here is a nice function i like to share with you because it so nice and handy feature. I wanted to get rid off the parent::methodName(myVar1, myVar2, myVar3 etc.....) construction so i wrote a shortcut to this notation. The only thing you have to do is calling $this->inherited() (or parent::inherited()) to call the same function with the same parameters in the parent class. It is also possible to specify other parameters if you like. You can also use this inside constructors/destructors.

To use this example, put it in the base class of all objects.You also need the simple function below to test if an array is valid (from a self-build library) but you are free to change it to your own needs ;-):

<?php
function suIsValidArray( &$a, &$iCount null )
{
  
$iCount 0;
  return ( 
is_array$a ) and (( $iCount = @count$a )) > ));  
}
?>


The inherited function/construction is familiar language construction in Object Pascal/Delphi (wonderful language). If you have any comments, please enter a note.   

Here it is:

<?php 
    
public function inherited() 
    {
       
// Use DEBUG backtrace to trace caller function
      
$bt debug_backtrace();
      
$bt $bt]; // List is in reversed order, 0 reffers to this function so get previous one
      
      
if( !suIsValidArray$bt ))
      { return; }
      
      
$sClassName $bt["class"];
      
$sParentClassName get_parent_class$sClassName );
      if( empty( 
$sClassName ) or empty( $sParentClassName ) or $sParentClassName == $sClassName )
      { return; } 
      
      
$sFuncName $bt["function"];
       
// constructor or destructor called (old fashion way)?
      
if( ( $bIsConstruct = ( $sFuncName == $sClassName )) or ( $sFuncName == "_".$sClassName ) )
      { 
          
// get parent constructor/destructor
          
$sFuncName = (( !$bIsConstruct ) ? "_" "" ).$sParentClassName;
        if( 
$sFuncName == (( !$bIsConstruct ) ? "_" "" ).$sClassName )
        { return; }
      }      
       
      if( 
method_exists$sParentClassName$sFuncName ))
       { 
             
// If there are parameters specified, use these
         
$args func_get_args();
         if( !
suIsValidArray$args ))
          { 
$args = &$bt["args"]; } // otherwise use previous function parameters if any 
      
           
$iCount 0
           
$sArgs "";
        if( 
suIsValidArray$args$iCount ))
         { 
           for( 
$i 0$i $iCount$i++ )
            { 
$sArgs.="&$"."args[$i]".( $i < ($iCount-1) ? "," "" ); }
         }    
         
         
// Simple, evaluate it, this is possible because it is done inside the class itself, and
         // the parent class is already created because is a part of the class structure, no worry, no scope issues   
        
eval( "$"."result = $sParentClassName::".$sFuncName."($sArgs);" );
        return @
$result
       }  
    }
?>

[#8] csaba dot dobai at php-sparcle dot com [2009-02-03 09:54:02]

For the 'late static binding' topic I published a code below, that demonstrates a trick for how to setting variable value in the late class, and print that in the parent (or the parent's parent, etc.) class.

<?php

class cA
{
    

    
protected static $item 'Foo';
    
    

    
protected static $other 'cA';
    
    public static function 
method()
    {
        print 
self::$item."\r\n"// It prints 'Foo' on everyway... :(
        
print self::$other."\r\n"// We just think that, this one prints 'cA' only, but... :)
    
}
    
    public static function 
setOther($val)
    {
        
self::$other $val// Set a value in this scope.
    
}
}

class 
cB extends cA
{
    

    
protected static $item 'Bar';
    
    public static function 
setOther($val)
    {
        
self::$other $val;
    }
}

class 
cC extends cA
{
    

    
protected static $item 'Tango';
    
    public static function 
method()
    {
        print 
self::$item."\r\n"// It prints 'Foo' on everyway... :(
        
print self::$other."\r\n"// We just think that, this one prints 'cA' only, but... :)
    
}
    
    

}

class 
cD extends cA
{
    

    
protected static $item 'Foxtrot';
    
    

}

cB::setOther('cB'); // It's cB::method()!
cB::method(); // It's cA::method()!
cC::setOther('cC'); // It's cA::method()!
cC::method(); // It's cC::method()!
cD::setOther('cD'); // It's cA::method()!
cD::method(); // It's cA::method()!



?>

[#9] luka8088 at gmail dot com [2009-01-24 15:15:12]

Little static trick to go around php strict standards ...
Function caller founds an object from which it was called, so that static method can alter it, replacement for $this in static function but without strict warnings :)

<?php

error_reporting
(E_ALL E_STRICT);

function 
caller () {
  
$backtrace debug_backtrace();
  
$object = isset($backtrace[0]['object']) ? $backtrace[0]['object'] : null;
  
$k 1;
        
  while (isset(
$backtrace[$k]) && (!isset($backtrace[$k]['object']) || $object === $backtrace[$k]['object']))
    
$k++;

  return isset(
$backtrace[$k]['object']) ? $backtrace[$k]['object'] : null;
}

class 
{

  public 
$data 'Empty';
  
  function 
set_data () {
    
b::set();
  }

}

class 
{

  static function 
set () {
    
// $this->data = 'Data from B !';
    // using this in static function throws a warning ...
    
caller()->data 'Data from B !';
  }

}

$a = new a();
$a->set_data();
echo 
$a->data;

?>


Outputs: Data from B !

No warnings or errors !

[#10] barss dot dev at gmail dot com [2008-07-01 03:47:38]

Nice trick with scope resolution
<?php
    
class A
    
{
        public function 
TestFunc()
        {
            return 
$this->test;
        }
    }

    class 
B
    
{
        public 
$test;

        public function 
__construct()
        {
            
$this->test "Nice trick";
        }

        public function 
GetTest()
        {
            return 
A::TestFunc();
        }
    }

    
$b = new B;
    echo 
$b->GetTest();
?>


will output

Nice trick

[#11] richard at richard-sumilang dot com [2008-03-24 06:27:21]

Actually, for people not using PHP 5.3 yet you should try avoiding the use of a eval() at all costs! THere are too many security risks and dirty code that come from using eval. If you want to call a static method from a class then you can use call_user_func() instead which is much safer.

Example:

clas Foo{

  public static method Bar(){
    echo "Hello world!";
  }

}

And to execute that with call_user_func you would do the following:

call_user_func(array('Foo', 'bar') [, $params] );

Thanks,
- Richard S.

[#12] mongoose643 at gmail dot com [2007-02-13 00:11:26]

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(null1);
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_erase1);
print_r($elements_left);
echo 
"<br>";
echo 
"Enjoy!";

?>

[#13] developit at mail dot ru [2006-01-27 03:57:07]

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 
extends A
{
    protected 
$x 'B';
    public function 
f()
    {
        return 
'{'.$this->x.'}';
    }
}

class 
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]

[#14] Kristof Coomans [2005-11-25 03:08:24]

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)

[#15] HuugjeWeg [2005-04-29 05:58:49]

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

[#16] thenewparadigm at hotmail dot com [2005-03-05 09:43:33]

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.

[#17] ian at [first name]henderson dot org [2005-01-31 22:43:13]

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.

上一篇: 下一篇: