2010-02-23 33 views
5

Tôi đã gặp một số hành vi không mong muốn với các biến tĩnh được xác định bên trong các phương thức đối tượng được chia sẻ trên các phiên bản. Đây có lẽ là hành vi đã biết, nhưng khi tôi duyệt tài liệu PHP, tôi không thể tìm thấy các cá thể của các biến được định nghĩa tĩnh trong các phương thức đối tượng.Tĩnh trong phương pháp không tĩnh được chia sẻ giữa các trường hợp

Đây là một giảm hành vi tôi đã đi qua:

<?php 

class Foo { 
    public function dofoo() { 
    static $i = 0; 
    echo $i++ . '<br>'; 
    } 
} 

$f = new Foo; 
$g = new Foo; 

$f->dofoo(); // expected 0, got 0 
$f->dofoo(); // expected 1, got 1 
$f->dofoo(); // expected 2, got 2 

$g->dofoo(); // expected 0, got 3 
$g->dofoo(); // expected 1, got 4 
$g->dofoo(); // expected 2, got 5 

Bây giờ, tôi lại có thể ngờ $i để được tĩnh mỗi trường hợp, nhưng trong thực tế $i được chia sẻ giữa các trường hợp. Đối với sự chỉnh sửa của riêng tôi, ai đó có thể giải thích lý do tại sao đây là trường hợp, và nơi nó được ghi lại trên php.net?

Trả lời

6

Đây là số very definition tĩnh.

Nếu bạn muốn các thành viên để được cụ thể cho một thể hiện của một đối tượng, sau đó bạn sử dụng class properties

ví dụ

<?php 

class Foo 
{ 
    protected $_count = 0; 
    public function doFoo() 
    { 
     echo $this->_count++, '<br>'; 
    } 
} 

Edit: Ok, tôi liên kết các tài liệu hướng dẫn để các thuộc tính OOP tĩnh. Khái niệm này là như nhau mặc dù. Nếu bạn đọc variable scope docs bạn sẽ thấy:

Note: khai báo tĩnh được giải quyết trong thời gian biên dịch.

Vì vậy, khi tập lệnh của bạn được biên dịch (trước khi thực thi), tĩnh là "thiết lập" (không chắc chắn nên sử dụng thuật ngữ nào). Không có vấn đề bao nhiêu đối tượng bạn nhanh chóng, khi chức năng đó được "xây dựng" biến tĩnh tham chiếu cùng một bản sao như mọi người khác.

+0

Tài liệu đó dành cho các thuộc tính và phương thức lớp tĩnh, không phải các biến tĩnh trong một phương thức. –

+0

Adam: Trong PHP5, chúng là một và giống nhau. Tĩnh tĩnh. – hobodave

+0

Trong tâm trí của tôi, '$ f-> dofoo()' không phải là phương thức giống như '$ g-> dofoo()'. Rõ ràng các nhà phát triển PHP không thuộc cùng một tâm trí. :) –

1

Đó là tĩnh là gì, nó là cùng một biến trên tất cả các phiên bản của lớp.

Bạn muốn viết điều này để biến là một thành viên riêng của cá thể của lớp.

class Foo { 
    private $i = 0; 
    public function dofoo() { 
    echo $this->i++ . '<br>'; 
    } 
} 
1

Từ khóa tĩnh có thể được sử dụng with variables hoặc sử dụng with class methods and properties. Các biến tĩnh đã được giới thiệu trong PHP 4 (tôi nghĩ rằng, nó có thể đã được trước đó). lớp thành viên/phương pháp tĩnh đã được giới thiệu trong PHP 5.

Vì vậy, mỗi hướng dẫn, một tĩnh biến

Một tính năng quan trọng của Phạm vi biến là biến tĩnh. Biến tĩnh chỉ tồn tại trong một hàm địa phương là phạm vi , nhưng nó không mất giá trị khi thực hiện chương trình rời khỏi phạm vi này.

Điều này phù hợp với hành vi bạn mô tả. Nếu bạn muốn một biến cho mỗi instance, sử dụng một thành viên class thông thường.

2

Tôi đồng ý rằng tài liệu PHP hiện tại không đủ rõ ràng về chính xác "phạm vi" có nghĩa là cho biến tĩnh bên trong phương thức không tĩnh.

Đó là tất nhiên đúng (như hobodave chỉ ra) rằng "tĩnh" thường có nghĩa là "mỗi lớp", nhưng thuộc tính của lớp tĩnh là không biến chính xác những điều tương tự như tĩnh trong một phương pháp (không tĩnh), trong đó sau này được "scoped" theo phương thức (mọi phương thức trong một lớp có thể có biến $ foo tĩnh của riêng nó, nhưng có thể có tối đa một thành viên lớp tĩnh có tên là $ foo).

Và tôi cho rằng mặc dù PHP 5 hành vi phù hợp ("tĩnh" luôn luôn có nghĩa là "một ví dụ chia sẻ mỗi class"), nó là không cách duy nhất mà PHP thể cư xử. Ví dụ, hầu hết mọi người sử dụng các biến chức năng tĩnh để tồn tại trạng thái tồn tại qua các cuộc gọi hàm, và đối với các chức năng toàn cục, hành vi của PHP chính là điều mà hầu hết mọi người mong đợi. Vì vậy, chắc chắn có thể tưởng tượng một trình thông dịch PHP duy trì trạng thái của các biến phương thức nhất định trên lời gọi phương thức và thực hiện "mỗi trường hợp", và đó thực sự là những gì tôi cũng dự kiến ​​xảy ra khi lần đầu tiên tôi khai báo biến phương thức cục bộ .

0

Ups 7 năm một thời gian dài nhưng dù sao ở đây nó đi.

Tất cả các lớp đều có hàm tạo mặc định tại sao tôi lại nói điều này?!? Bởi vì nếu bạn xác định một hành vi mặc định trong hàm khởi tạo, mỗi cá thể của lớp sẽ bị ảnh hưởng.

Ví dụ:

namespace Statics; 

class Foo 
{ 
    protected static $_count; 

    public function Bar() 
    { 
     return self::$_count++; 
    } 

    public function __construct() 
    { 
     self::$_count = 0; 
    } 
} 

Hệ quả là:

require 'Foo.php'; 

use Statics\Foo; 

$bar = new Foo(); 
echo $bar->bar().'<br>'; 
echo $bar->bar().'<br>'; 
echo $bar->bar().'<br>'; 

$barcode = new Foo(); 
echo $barcode->bar().'<br>'; 
echo $barcode->bar().'<br>'; 
echo $barcode->bar().'<br>'; 

0 
1 
2 
0 
1 
2 

Mỗi trường hợp mới từ tầng lớp thượng lưu sẽ bắt đầu từ 0! Hành vi đếm tĩnh sẽ KHÔNG được chia sẻ trên nhiều phiên bản vì nó sẽ bắt đầu từ giá trị được gán trong hàm tạo.

Nếu bạn cần chia sẻ dữ liệu trên nhiều trường hợp, tất cả những gì bạn cần làm là xác định biến tĩnh và gán dữ liệu mặc định bên ngoài hàm tạo!

Ví dụ:

namespace Statics; 

class Foo 
{ 
    //default value 
    protected static $_count = 0; 

    public function Bar() 
    { 
     return self::$_count++; 
    } 

    public function __construct() 
    { 
     //do something else 
    } 
} 

Hệ quả là:

require 'Foo.php'; 

use Statics\Foo; 

$bar = new Foo(); 
echo $bar->bar().'<br>'; 
echo $bar->bar().'<br>'; 
echo $bar->bar().'<br>'; 

$barcode = new Foo(); 
echo $barcode->bar().'<br>'; 
echo $barcode->bar().'<br>'; 
echo $barcode->bar().'<br>'; 

0 
1 
2 
3 
4 
5 

Như bạn có thể thấy kết quả là hoàn toàn khác nhau, việc phân bổ không gian bộ nhớ là như nhau ở giữa các trường lớp nhưng nó có thể tạo ra kết quả khác nhau dựa trên cách bạn xác định giá trị mặc định.

Tôi hy vọng điều đó đã giúp ích, không phải các câu trả lời ở trên là sai, nhưng tôi cảm thấy rằng điều quan trọng là phải hiểu tất cả khái niệm từ góc độ này.

Trân trọng, từ Bồ Đào Nha!

Các vấn đề liên quan