Apakah mungkin untuk membuat kelas statis di PHP (seperti di C #)?

140

Saya ingin membuat kelas statis di PHP dan membuatnya berperilaku seperti di C #, jadi

  1. Pembuat secara otomatis dipanggil pada panggilan pertama ke kelas
  2. Instansiasi tidak diperlukan

Sesuatu seperti ini ...

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

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

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

Hello::greet(); // Hello There!
aleemb
sumber
Bisakah Anda menjelaskan secara singkat seperti apa seharusnya kelas statis berperilaku? Apakah ini implementasi Utilitas?
xtofl
Hanya membuang pendapat saya sendiri di luar sana, tetapi dari pengalaman saya di PHP, demi kewarasan, testabilitas, dan skalabilitas, kelas statis harus hampir seluruhnya tanpa kewarganegaraan, menyajikan api seperti pemrograman yang lebih fungsional daripada yang berorientasi objek, dan umumnya adalah paling baik digunakan sebagai fasad aksesibilitas untuk objek yang dibuat sepenuhnya atau pembungkus utilitas untuk pembantu atau konstruksi serupa jika mereka digunakan sama sekali.
mopsyd

Jawaban:

202

Anda dapat memiliki kelas statis di PHP tetapi mereka tidak memanggil konstruktor secara otomatis (jika Anda mencoba dan memanggil self::__construct()Anda akan mendapatkan kesalahan).

Oleh karena itu, Anda harus membuat initialize()fungsi dan memanggilnya di setiap metode:

<?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!


?>
Greg
sumber
20
Saya cukup sering melakukan ini hanya untuk menyelesaikan semua fungsi di satu tempat. Utilitas IE :: doSomethingUseful ();
smack0007
16
Alih-alih Therefore you'd have to create an initialize() function and call it in each method:akan lebih mudah untuk membuat initializefungsi publik dan memanggilnya tepat setelah deklarasi kelas.
chacham15
4
Saya tahu ini cukup lama, tetapi sekarang Anda dapat menggunakan sihir __callStatic sehingga ketika Anda memanggil metode statis atau apa pun, itu akan memanggil pertama __callStatic, di sana Anda dapat melihat apakah itu diinisialisasi dan kemudian melakukan self::$methodatau apa pun yang Anda panggil. Jika masih memanggil metode secara langsung, coba ubah semuanya menjadi pribadi dan lihat di sana.
matiaslauriti
1
Apa yang terjadi jika dua utas memanggil salam pada saat yang bersamaan? Karena tidak ada sinkronisasi, tidak akan menginisialisasi dipanggil dua kali (yang dalam hal ini baik-baik saja, tetapi dalam banyak kasus lain tidak). Atau apakah php single threaded dan non-preemptive seperti node?
John Little
54

Selain jawaban Greg, saya akan merekomendasikan untuk menyetel konstruktor pribadi sehingga tidak mungkin untuk membuat instance kelas.

Jadi menurut pendapat saya ini adalah contoh yang lebih lengkap berdasarkan Greg's:

<?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!


?>
Phil
sumber
1
Ini adalah pendekatan yang bagus, namun fungsi konstruksi tidak dapat diimplementasikan jika singelton Anda mewarisi dari objek tertentu yang memerlukan konstruktor publik.
Eric Herlitz
4
@EricHerlitz Pertanyaan ini bukan tentang lajang, ini tentang kelas statis. Mengapa Anda ingin membuat kelas statis yang mewarisi dari kelas yang dimaksudkan untuk dipakai?
Mark Amery
3
Sama-sama mendeklarasikan kelas sebagai abstrak dengan mencegahnya dibuat instance-nya dan masih mengizinkan panggilan ke metode statis.
Bstoney
24

Anda dapat memiliki kelas seperti "statis". tetapi saya kira, ada sesuatu yang sangat penting hilang: di php Anda tidak memiliki siklus aplikasi, jadi Anda tidak akan mendapatkan statis nyata (atau tunggal) di seluruh aplikasi Anda ...

lihat Singleton di PHP

Andreas Niedermair
sumber
1
Kelas Statis dan Lajang hanyalah 2 hal yang berbeda.
Max Cuttins
4
final Class B{

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

Struktur b disebut penangan tunggal Anda juga bisa melakukannya di a

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

ini adalah penggunaan tunggal $a = a::getA(...);

borrel
sumber
3

Saya biasanya lebih suka menulis kelas non statis biasa dan menggunakan kelas pabrik untuk membuat instance tunggal (sudo statis) objek.

Dengan cara ini konstruktor dan destruktor bekerja seperti biasa, dan saya dapat membuat instance non-statis tambahan jika saya mau (misalnya koneksi DB kedua)

Saya menggunakan ini sepanjang waktu dan sangat berguna untuk membuat penangan sesi penyimpanan DB kustom, seperti ketika halaman berakhir, destruktor akan mendorong sesi ke database.

Keuntungan lainnya adalah Anda dapat mengabaikan pesanan yang Anda panggil karena semuanya akan diatur sesuai permintaan.

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

Kelas DB ...

class clsDB {

    $regular_public_variables = "whatever";

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

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

Di mana pun Anda ingin menggunakannya, panggil saja ...

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

Kemudian perlakukan saja semua metode sebagai non-statis (karena memang demikian)

echo $static_instance->getvar();
dave.zap
sumber
1
Ini sebenarnya adalah implementasi pola tunggal, dan seharusnya tidak digunakan - tetap berpegang pada injeksi ketergantungan, yang dapat diuji dan membuatnya mudah untuk di-debug.
Thomas Hansen
1
Dapatkah Anda memberikan contoh cara menggunakan injeksi ketergantungan untuk jawaban ini dan bagaimana membuatnya lebih dapat diuji?
cjsimon
2

objek tidak dapat didefinisikan secara statis tetapi ini berfungsi

final Class B{
  static $var;
  static function init(){
    self::$var = new A();
}
B::init();
borrel
sumber
1
Andreas Niedermair: begitulah cara kerja php (app-cycle = satu permintaan) Tetapi singleton (pada satu yang hidup dalam permintaan) adalah kepemilikan dalam php (dalam php, singleton adalah objek yang memiliki 1 instance (dalam aplikasi- siklus)
borrel