Sự khác biệt giữa :: (dấu hai chấm) và -> (mũi tên) trong PHP là gì?


196

Có hai cách khác nhau để truy cập các phương thức trong PHP, nhưng sự khác biệt là gì?

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

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

Tôi giả sử ->(dấu gạch ngang lớn hơn dấu hoặc chevron) được sử dụng cho các hàm cho các biến và ::(dấu hai chấm) được sử dụng cho các hàm cho các lớp. Chính xác?

=>toán tử gán chỉ được sử dụng để gán dữ liệu trong một mảng? Điều này có trái ngược với =toán tử gán được sử dụng để khởi tạo hoặc sửa đổi một biến không?



Câu trả lời:


172

Khi phần bên trái là một đối tượng, bạn sử dụng ->. Nếu không, bạn sử dụng ::.

Điều này có nghĩa ->là phần lớn được sử dụng để truy cập các thành viên thể hiện (mặc dù nó cũng có thể được sử dụng để truy cập các thành viên tĩnh, việc sử dụng đó không được khuyến khích), trong khi ::thường được sử dụng để truy cập các thành viên tĩnh (mặc dù trong một số trường hợp đặc biệt, nó được sử dụng để truy cập các thành viên thể hiện ).

Nói chung, ::được sử dụng cho độ phân giải phạm vi , và nó có thể có hoặc là một tên lớp, parent, self, hoặc (trong PHP 5.3) staticsang bên trái của nó. parentđề cập đến phạm vi của siêu lớp của lớp nơi nó được sử dụng; selfđề cập đến phạm vi của lớp nơi nó được sử dụng; staticđề cập đến "phạm vi được gọi" (xem các ràng buộc tĩnh muộn ).

Quy tắc là một cuộc gọi với ::là một cuộc gọi thể hiện khi và chỉ khi:

  • phương thức đích không được khai báo là tĩnh
  • có một bối cảnh đối tượng tương thích tại thời điểm cuộc gọi, nghĩa là những điều này phải đúng:
    1. cuộc gọi được thực hiện từ một bối cảnh $thistồn tại và
    2. lớp của $thishoặc là lớp của phương thức được gọi hoặc lớp con của nó.

Thí dụ:

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

Đầu ra:

B :: $ prop_static: B :: $ prop_static giá trị
B :: func_static (): trong B :: func_static

$ b-> prop_instance: B :: $ prop_instance giá trị
$ b-> func_static (): trong B :: func_static

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

$ a-> dyn ():
trong A :: callDocate
trong dyn động (__callStatic)

$ b-> dyn ():
trong A :: callDocate
trong dyn động (__call)

3
" ->Chủ yếu được sử dụng để truy cập các thành viên thể hiện (mặc dù nó cũng có thể được sử dụng để truy cập các thành viên tĩnh, việc sử dụng như vậy không được khuyến khích)" Tôi không biết điều đó có thể xảy ra. Vì vậy, nếu nó "hoạt động" theo một cách nào đó khi được sử dụng để truy cập các thành viên tĩnh - người ta sẽ mong đợi sự khác biệt nào trong hành vi nếu người ta sử dụng nó không đúng như thế này? Chỉ tò mò thôi.
lucideer

4
@lucideer Trong trường hợp các phương thức tĩnh, đó là một câu hỏi về thực hành tốt (phương thức này thuộc về chính lớp đó), nhưng PHP không phàn nàn nếu gọi một phương thức tĩnh với ->. Tất nhiên, bạn có thể cần khởi tạo lớp chỉ để gọi một phương thức tĩnh, do đó, cũng có một điểm nhấn hiệu năng. Với tài sản, tuy nhiên, có nhiều vấn đề hơn. Một cảnh báo STRICT được đưa ra và nó có thể hoặc không thể hoạt động . Lưu ý rằng điều ngược lại cũng đúng - bạn có thể gọi một phương thức cá thể một cách tĩnh, nhưng điều này thậm chí còn tệ hơn (và bạn không thể sử dụng $thistrong việc thực hiện phương thức đó).
Artefacto

52

::được sử dụng trong bối cảnh tĩnh , tức là. khi một số phương thức hoặc thuộc tính được khai báo là tĩnh:

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

$result = Math::sin(123);

Ngoài ra, ::toán tử (Toán tử phân giải phạm vi, còn gọi là Paamayim Nekudotayim ) được sử dụng trong ngữ cảnh động khi bạn gọi một phương thức / thuộc tính của lớp cha:

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);
    }
}

->được sử dụng trong bối cảnh động , tức là. khi bạn đối phó với một số thể hiện của một số lớp:

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

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

Nhân tiện: Tôi không nghĩ rằng sử dụng Symfony là một ý tưởng hay khi bạn không có bất kỳ trải nghiệm OOP nào.


24

Trên thực tế bằng biểu tượng này, chúng ta có thể gọi một phương thức lớp là tĩnh và không bị phụ thuộc vào khởi tạo khác ...

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;
    }
}

Ở đây doWrite()hàm không phụ thuộc vào bất kỳ phương thức hoặc biến nào khác, và nó là một phương thức tĩnh. Đó là lý do tại sao chúng ta có thể gọi phương thức này bởi toán tử này mà không khởi tạo đối tượng của lớp này.

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

Nhưng nếu bạn muốn gọi writephương thức theo cách này, nó sẽ phát sinh lỗi vì nó phụ thuộc vào khởi tạo.


15

Các =>nhà điều hành được sử dụng để cặp khóa-giá trị assign trong một mảng kết hợp. Ví dụ:

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

Ý nghĩa của nó là tương tự trong foreachtuyên bố:

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

14

Sự khác biệt giữa các phương thức và thuộc tính tĩnh và tức thời dường như là một trong những trở ngại lớn nhất đối với những người mới bắt đầu với OOP PHP trong PHP 5.

Toán tử dấu hai chấm (được gọi là Paamayim Nekudotayim từ tiếng Do Thái - trivia) được sử dụng khi gọi một đối tượng hoặc thuộc tính từ ngữ cảnh tĩnh . Điều này có nghĩa là một thể hiện của đối tượng chưa được tạo.

Ngược lại, toán tử mũi tên gọi các phương thức hoặc thuộc tính từ tham chiếu của một thể hiện của đối tượng.

Các phương thức tĩnh có thể đặc biệt hữu ích trong các mô hình đối tượng được liên kết với cơ sở dữ liệu để tạo và xóa phương thức, vì bạn có thể đặt giá trị trả về cho id bảng được chèn và sau đó sử dụng hàm tạo để khởi tạo đối tượng theo id hàng.


2

Vâng, tôi chỉ đánh đầu tiên của tôi 'PHP Parse error: syntax error, unexpected T_PAAMAYIM_NEKUDOTAYIM'. Thật tệ, tôi đã có một $instance::method()cái mà lẽ ra phải có$instance->method() . Tôi thật ngốc.

Điều kỳ lạ là điều này vẫn hoạt động tốt trên máy cục bộ của tôi (chạy PHP 5.3.8) - không có gì, thậm chí không có cảnh báo với error_Vporting = E_ALL - nhưng hoàn toàn không phải trên máy chủ thử nghiệm, nó chỉ phát nổ với lỗi cú pháp và một màn hình trắng trong trình duyệt. Vì đăng nhập PHP đã bị tắt ở máy kiểm tra và công ty lưu trữ quá bận rộn để bật nó, điều đó không quá rõ ràng.

Vì vậy, từ cảnh báo: rõ ràng, một số cài đặt PHP sẽ cho phép bạn sử dụng $ instance :: method (), trong khi các cài đặt khác thì không.

Nếu bất cứ ai có thể mở rộng về lý do đó, xin vui lòng làm.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.