【问题标题】:What's the difference between :: (double colon) and -> (arrow) in PHP?PHP 中 :: (双冒号)和 -> (箭头)有什么区别?
【发布时间】:2011-03-11 13:14:23
【问题描述】:

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

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

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

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

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

【问题讨论】:

标签: php


【解决方案1】:

当左边部分是一个对象实例时,你使用->。否则,您使用::

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

一般来说,:: 用于scope resolution,它的左边可能有一个类名parentself 或(在 PHP 5.3 中)staticparent 指使用它的类的超类的范围; self 指使用它的类的范围; static 指的是“被调用范围”(参见late static bindings)。

规则是带有:: 的调用是实例调用当且仅当:

  • 目标方法未声明为静态
  • 在调用时有一个兼容的对象上下文,这意味着这些必须是真的:
    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) 中

【讨论】:

  • " -> 主要用于访问实例成员(虽然它也可以用于访问静态成员,但不鼓励这种用法)" 我不知道它可能是。因此,如果它在用于访问静态成员时以某种方式“起作用”——如果人们像这样错误地使用它,人们会期望它有什么不同的行为?只是出于好奇。
  • @lucideer 对于静态方法,这是一个良好实践的问题(该方法属于类本身),但如果使用-> 调用静态方法,PHP 不会报错。当然,您可能需要实例化类只是为了调用静态方法,因此也会影响性能。然而,对于属性,还有更多的问题。一个严格的警告被提出,它是may or may not work。请注意,反过来也是如此——您可以静态调用实例方法,但这更糟(并且您不能在此类方法实现中使用$this)。
【解决方案2】:

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

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 并不是一个好主意。

【讨论】:

    【解决方案3】:

    其实通过这个符号我们可以调用一个静态的类方法,不依赖于其他初始化...

    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方法,会产生错误,因为它依赖于初始化。

    【讨论】:

      【解决方案4】:

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

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

      foreach语句中的含义类似:

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

      【讨论】:

        【解决方案5】:

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

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

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

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

        【讨论】:

          【解决方案6】:

          是的,我刚刚打了我的第一个 '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(),而其他则不允许。

          如果有人能详细说明为什么会这样,请这样做。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2012-01-02
            • 1970-01-01
            • 2013-10-19
            • 2020-02-08
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多