PHP中的::(双冒号)和->(箭头)有什么区别?


196

有两种不同的方法来访问PHP中的方法,但是有什么区别?

$response->setParameter('foo', 'bar');

sfConfig::set('foo', 'bar');

我假设->(带有大于号或V形的破折号)用于变量的函数,::(双冒号)用于类的函数。正确?

=>赋值运算符仅用于分配数据的数组中?这与=用于实例化或修改变量的赋值运算符相反吗?



Answers:


172

如果左侧是对象实例,则使用->。否则,请使用::

这意味着它->通常用于访问实例成员(尽管它也可以用于访问静态成员,但不鼓励这种用法),而::通常用于访问静态成员(尽管在少数特殊情况下,它用于访问实例成员) )。

一般情况下,::被用于范围的分辨率,并且它可以具有一个类名称,parentself,或(在PHP 5.3)static到其左边。parent指使用该类的超类的范围;self指使用该类的范围;static指的是“被称为作用域”(请参阅后期静态绑定)。

规则是,::当且仅当:

  • 目标方法未声明为静态,并且
  • 调用时有一个兼容的对象上下文,这意味着这些必须是正确的:
    1. 呼叫是从$this存在的上下文中进行的,并且
    2. 的类$this是被调用方法的类或其子类。

例:

class A {
    public function func_instance() {
        echo "in ", __METHOD__, "\n";
    }
    public function callDynamic() {
        echo "in ", __METHOD__, "\n";
        B::dyn();
    }

}

class B extends A {
    public static $prop_static = 'B::$prop_static value';
    public $prop_instance = 'B::$prop_instance value';

    public function func_instance() {
        echo "in ", __METHOD__, "\n";
        /* this is one exception where :: is required to access an
         * instance member.
         * The super implementation of func_instance is being
         * accessed here */
        parent::func_instance();
        A::func_instance(); //same as the statement above
    }

    public static function func_static() {
        echo "in ", __METHOD__, "\n";
    }

    public function __call($name, $arguments) {
        echo "in dynamic $name (__call)", "\n";
    }

    public static function __callStatic($name, $arguments) {
        echo "in dynamic $name (__callStatic)", "\n";
    }

}

echo 'B::$prop_static: ', B::$prop_static, "\n";
echo 'B::func_static(): ', B::func_static(), "\n";
$a = new A;
$b = new B;
echo '$b->prop_instance: ', $b->prop_instance, "\n";
//not recommended (static method called as instance method):
echo '$b->func_static(): ', $b->func_static(), "\n";

echo '$b->func_instance():', "\n", $b->func_instance(), "\n";

/* This is more tricky
 * in the first case, a static call is made because $this is an
 * instance of A, so B::dyn() is a method of an incompatible class
 */
echo '$a->dyn():', "\n", $a->callDynamic(), "\n";
/* in this case, an instance call is made because $this is an
 * instance of B (despite the fact we are in a method of A), so
 * B::dyn() is a method of a compatible class (namely, it's the
 * same class as the object's)
 */
echo '$b->dyn():', "\n", $b->callDynamic(), "\n";

输出:

B :: $ prop_static:B :: $ prop_static值
B :: func_static():在B :: func_static中

$ b-> prop_instance:B :: $ prop_instance的值
$ b-> func_static():在B :: func_static中

$ b-> func_instance():
在B :: func_instance
在A :: func_instance
在A :: func_instance

$ a-> dyn():
在A :: callDynamic中
在动态dyn(__callStatic)中

$ b-> dyn():
在A :: callDynamic中
在动态dyn(__call)中

3
->主要用于访问实例成员(尽管它也可以用于访问静态成员,但不鼓励此类用法)”我不知道有没有可能。因此,如果它在用来访问静态成员时以某种方式“起作用”,那么,如果人们不正确地使用它,那么在行为上会有什么不同呢?只是出于好奇。
lucideer

4
@lucideer对于静态方法,这是一个好的实践问题(该方法属于类本身),但是如果使用调用静态方法,PHP不会抱怨->。当然,您可能只需要实例化该类以调用静态方法,因此也会影响性能。但是,关于属性,还有更多问题。发出STRICT警告,它可能会起作用也可能不会起作用。请注意,相反的情况也是如此-您可以静态调用实例方法,但这甚至更糟(并且不能$this在这种方法实现中使用)。
Artefacto

52

::用于静态上下文,即。当某些方法或属性声明为静态时:

class Math {
    public static function sin($angle) {
        return ...;
    }
}

$result = Math::sin(123);

此外,当您调用父类的方法/属性时,在动态上下文中使用::运算符(“范围解析运算符”,又名Paamayim Nekudotayim):

class Rectangle {
     protected $x, $y;

     public function __construct($x, $y) {
         $this->x = $x;
         $this->y = $y;
     }
}

class Square extends Rectangle {
    public function __construct($x) {
        parent::__construct($x, $x);
    }
}

->用于动态上下文,即。当您处理某个类的某个实例时:

class Hello {
    public function say() {
       echo 'hello!';
    }
}

$h = new Hello();
$h->say();

顺便说一句:当您没有任何OOP经验时,我认为使用Symfony并不是一个好主意。


24

实际上,通过此符号,我们可以调用静态的类方法,并且不依赖于其他初始化...

class Test {

    public $name;

    public function __construct() {
        $this->name = 'Mrinmoy Ghoshal';
    }

    public static function doWrite($name) {
        print 'Hello '.$name;
    }

    public function write() {
        print $this->name;
    }
}

这里的doWrite()函数不依赖于任何其他方法或变量,它是静态方法。这就是为什么我们可以通过此运算符调用此方法而无需初始化此类的对象的原因。

Test::doWrite('Mrinmoy'); // Output: Hello Mrinmoy.

但是,如果要以write这种方式调用该方法,则它将生成错误,因为它依赖于初始化。


15

=>运算符用于分配键-值对中的关联数组。例如:

$fruits = array(
  'Apple'  => 'Red',
  'Banana' => 'Yellow'
);

foreach语句中的含义相似:

foreach ($fruits as $fruit => $color)
  echo "$fruit is $color in color.";

14

静态和实例化方法与属性之间的差异似乎是那些刚开始使用PHP 5中的OOP PHP的最大障碍之一。

静态上下文中调用对象或属性时,将使用双冒号运算符(在希伯来语中称为Paamayim Nekudotayim-琐事)。这意味着该对象的实例尚未创建。

相反,箭头运算符从对象实例的引用中调用方法或属性。

静态方法在链接到数据库以创建和删除方法的对象模型中尤其有用,因为您可以将返回值设置为插入的表ID,然后使用构造函数通过行ID实例化对象。


2

是的,我刚刚打了我的第一个'PHP Parse error: syntax error, unexpected T_PAAMAYIM_NEKUDOTAYIM'。我的坏,我本来$instance::method()应该这样的$instance->method()。傻我

奇怪的是,这在我的本地机器上(运行PHP 5.3.8)仍然可以正常工作-什么都没有,甚至没有error_reporting = E_ALL的警告-但在测试服务器上却根本没有,只是因为语法错误而爆炸和浏览器中的白屏。由于在测试机上关闭了PHP日志记录,并且托管公司忙于将其打开,因此这不太明显。

因此,警告一词:显然,某些PHP安装将使您使用$ instance :: method(),而其他一些则没有。

如果有人可以解释为什么这样做,请这样做。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.