Có thể tạo các lớp tĩnh trong PHP (như trong C #) không?


139

Tôi muốn tạo một lớp tĩnh trong PHP và để nó hoạt động giống như trong C #, vì vậy

  1. Trình xây dựng được tự động gọi trong lần gọi đầu tiên đến lớp
  2. Không cần khởi tạo

Một cái gì đó thuộc loại này ...

static class Hello {
    private static $greeting = 'Hello';

    private __construct() {
        $greeting .= ' There!';
    }

    public static greet(){
        echo $greeting;
    }
}

Hello::greet(); // Hello There!

Bạn có thể giải thích ngắn gọn về một lớp tĩnh được cho là hành xử như thế nào không? Đây có phải là việc thực hiện một tiện ích?
xtofl

Chỉ cần đưa ra ý kiến ​​của riêng tôi ra khỏi đó, nhưng từ kinh nghiệm của tôi về PHP, vì sự tỉnh táo, khả năng kiểm tra và khả năng mở rộng, các lớp tĩnh nên hoàn toàn không trạng thái, trình bày một api giống như lập trình chức năng hơn so với một đối tượng hướng đối tượng, và nói chung là được sử dụng tốt nhất làm mặt tiền tiếp cận cho các đối tượng được khởi tạo đầy đủ hoặc trình bao bọc tiện ích cho người trợ giúp hoặc các cấu trúc tương tự nếu chúng thậm chí còn được sử dụng.
mopsyd

Câu trả lời:


200

Bạn có thể có các lớp tĩnh trong PHP nhưng chúng không tự động gọi hàm tạo (nếu bạn thử và gọi self::__construct()bạn sẽ gặp lỗi).

Do đó, bạn phải tạo một initialize()hàm và gọi nó trong mỗi phương thức:

<?php

class Hello
{
    private static $greeting = 'Hello';
    private static $initialized = false;

    private static function initialize()
    {
        if (self::$initialized)
            return;

        self::$greeting .= ' There!';
        self::$initialized = true;
    }

    public static function greet()
    {
        self::initialize();
        echo self::$greeting;
    }
}

Hello::greet(); // Hello There!


?>

20
Tôi khá thường xuyên làm điều này chỉ để bọc tất cả các chức năng ở một nơi. Tiện ích IE :: doS SomethingUseful ();
smack0007

16
Thay vì Therefore you'd have to create an initialize() function and call it in each method:nó sẽ dễ dàng hơn để thực hiện initializemột chức năng công khai và gọi nó ngay sau khi tuyên bố của lớp.
chacham15

4
Tôi biết điều này khá cũ, nhưng bây giờ bạn có thể sử dụng ma thuật __callStatic vì vậy khi bạn gọi bất kỳ phương thức tĩnh hoặc bất cứ điều gì, đầu tiên nó sẽ gọi __callStatic, ở đó bạn có thể thấy nếu nó được khởi tạo và sau đó làm self::$methodhoặc bất cứ điều gì bạn đang gọi. Nếu nó vẫn đang gọi phương thức trực tiếp, hãy thử thay đổi mọi thứ thành riêng tư và xem ở đó.
matiaslauriti

1
Điều gì xảy ra nếu hai chủ đề gọi chào cùng một lúc? Vì không có đồng bộ hóa, sẽ không được gọi khởi tạo hai lần (trong trường hợp này là ổn, nhưng trong nhiều trường hợp khác thì không). Hoặc là php đơn luồng và không ưu tiên như nút?
John Little

53

Ngoài câu trả lời của Greg, tôi khuyên bạn nên đặt công cụ xây dựng riêng tư để không thể khởi tạo lớp.

Vì vậy, theo ý kiến ​​khiêm tốn của tôi, đây là một ví dụ đầy đủ hơn dựa trên ví dụ của Greg:

<?php

class Hello
{
    /**
     * Construct won't be called inside this class and is uncallable from
     * the outside. This prevents instantiating this class.
     * This is by purpose, because we want a static class.
     */
    private function __construct() {}
    private static $greeting = 'Hello';
    private static $initialized = false;

    private static function initialize()
    {
        if (self::$initialized)
            return;

        self::$greeting .= ' There!';
        self::$initialized = true;
    }

    public static function greet()
    {
        self::initialize();
        echo self::$greeting;
    }
}

Hello::greet(); // Hello There!


?>

1
Đây là một cách tiếp cận tuyệt vời, tuy nhiên chức năng xây dựng không thể được thực hiện nếu singelton của bạn kế thừa từ các đối tượng nhất định yêu cầu một nhà xây dựng công cộng.
Eric Herlitz

4
@EricHerlitz Câu hỏi này không phải về singletons, mà là về các lớp tĩnh. Tại sao bạn muốn tạo một lớp tĩnh kế thừa từ một lớp có nghĩa là được khởi tạo?
Đánh dấu Amery

3
Khai báo một cách công bằng lớp là trừu tượng với việc ngăn chặn nó được khởi tạo và vẫn cho phép các cuộc gọi đến các phương thức tĩnh.
bstoney

24

bạn có thể có các lớp giống như "tĩnh". nhưng tôi cho rằng, thiếu một thứ gì đó thực sự quan trọng: trong php bạn không có chu trình ứng dụng, vì vậy bạn sẽ không nhận được một tĩnh thực (hoặc singleton) trong toàn bộ ứng dụng của mình ...

xem Singleton trong PHP


1
Lớp tĩnh và Singletons chỉ là 2 thứ khác nhau.
Max Cuttins

4
final Class B{

    static $staticVar;
    static function getA(){
        self::$staticVar = New A;
    }
}

cấu trúc của b là calld một trình xử lý singeton bạn cũng có thể làm điều đó trong một

Class a{
    static $instance;
    static function getA(...){
        if(!isset(self::$staticVar)){
            self::$staticVar = New A(...);
        }
        return self::$staticVar;
    }
}

đây là cách sử dụng đơn $a = a::getA(...);


3

Tôi thường thích viết các lớp không tĩnh thông thường và sử dụng một lớp nhà máy để khởi tạo các thể hiện đơn (sudo static) của đối tượng.

Cách này hàm tạo và hàm hủy hoạt động như bình thường và tôi có thể tạo thêm các thể hiện không tĩnh nếu tôi muốn (ví dụ: kết nối DB thứ hai)

Tôi sử dụng điều này mọi lúc và đặc biệt hữu ích để tạo trình xử lý phiên lưu trữ DB tùy chỉnh, vì khi trang kết thúc, hàm hủy sẽ đẩy phiên tới cơ sở dữ liệu.

Một lợi thế khác là bạn có thể bỏ qua thứ tự bạn gọi mọi thứ vì mọi thứ sẽ được thiết lập theo yêu cầu.

class Factory {
    static function &getDB ($construct_params = null)
    {
        static $instance;
        if( ! is_object($instance) )
        {
            include_once("clsDB.php");
            $instance = new clsDB($construct_params);   // constructor will be called
        }
        return $instance;
    }
}

Lớp DB ...

class clsDB {

    $regular_public_variables = "whatever";

    function __construct($construct_params) {...}
    function __destruct() {...}

    function getvar() { return $this->regular_public_variables; }
}

Bất cứ nơi nào bạn muốn sử dụng nó chỉ cần gọi ...

$static_instance = &Factory::getDB($somekickoff);

Sau đó, chỉ cần coi tất cả các phương thức là không tĩnh (vì chúng là)

echo $static_instance->getvar();

1
Đây thực sự là một triển khai mẫu đơn lẻ và thực sự không nên được sử dụng - thay vào đó, sử dụng phép tiêm phụ thuộc, điều này có thể kiểm tra được và giúp dễ dàng gỡ lỗi.
Thomas Hansen

1
Bạn có thể đưa ra một ví dụ về cách sử dụng tiêm phụ thuộc cho câu trả lời này và làm thế nào để làm cho nó dễ kiểm tra hơn?
cjsimon

2

đối tượng không thể được định nghĩa tĩnh nhưng điều này hoạt động

final Class B{
  static $var;
  static function init(){
    self::$var = new A();
}
B::init();

1
Andreas Niedermair: đó là cách php hoạt động (app-chu kỳ = một yêu cầu) Nhưng một singleton (trên một người sống trong yêu cầu) là một khả năng tồn tại trong php (trong php một singleton là một đối tượng có 1 thể hiện (trong ứng dụng- chu kỳ)
borrel
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.