Dua alasan utama untuk tidak menggunakan metode statis adalah:
- kode menggunakan metode statis sulit untuk diuji
- kode menggunakan metode statis sulit untuk diperluas
Memiliki panggilan metode statis di dalam beberapa metode lain sebenarnya lebih buruk daripada mengimpor variabel global. Di PHP, kelas adalah simbol global, jadi setiap kali Anda memanggil metode statis, Anda mengandalkan simbol global (nama kelas). Ini adalah kasus ketika global itu jahat. Saya punya masalah dengan pendekatan semacam ini dengan beberapa komponen Zend Framework. Ada kelas yang menggunakan pemanggilan metode statis (pabrik) untuk membangun objek. Tidak mungkin bagi saya untuk memasok pabrik lain ke instance itu untuk mendapatkan objek yang disesuaikan dikembalikan. Solusi untuk masalah ini adalah dengan hanya menggunakan instance dan metode instace dan menegakkan lajang dan sejenisnya di awal program.
Miško Hevery , yang bekerja sebagai Agile Coach di Google, memiliki teori yang menarik, atau lebih tepatnya menyarankan, bahwa kita harus memisahkan waktu pembuatan objek dari saat kita menggunakan objek. Jadi siklus hidup suatu program terbagi dua. Bagian pertama ( main()
metode katakanlah), yang menangani semua objek pengkabelan dalam aplikasi Anda dan bagian yang melakukan pekerjaan yang sebenarnya.
Jadi alih-alih memiliki:
class HttpClient
{
public function request()
{
return HttpResponse::build();
}
}
Kita sebaiknya melakukan:
class HttpClient
{
private $httpResponseFactory;
public function __construct($httpResponseFactory)
{
$this->httpResponseFactory = $httpResponseFactory;
}
public function request()
{
return $this->httpResponseFactory->build();
}
}
Dan kemudian, di halaman indeks / utama, kami akan melakukan (ini adalah langkah pengkabelan objek, atau waktu untuk membuat grafik instance yang akan digunakan oleh program):
$httpResponseFactory = new HttpResponseFactory;
$httpClient = new HttpClient($httpResponseFactory);
$httpResponse = $httpClient->request();
Gagasan utamanya adalah memisahkan ketergantungan dari kelas Anda. Dengan cara ini, kode ini jauh lebih mudah dikembangkan dan, bagian terpenting bagi saya, dapat diuji. Mengapa lebih penting untuk diuji? Karena saya tidak selalu menulis kode perpustakaan, jadi ekstensibilitas tidak terlalu penting, tetapi testabilitas penting ketika saya melakukan refactoring. Bagaimanapun, kode yang dapat diuji biasanya menghasilkan kode yang dapat diperluas, jadi ini bukan benar-benar situasi yang baik.
Miško Hevery juga membuat perbedaan yang jelas antara lajang dan lajang (dengan atau tanpa huruf kapital S). Perbedaannya sangat sederhana. Lajang dengan huruf "s" kecil diberlakukan oleh kabel di indeks / utama. Anda instantiate objek kelas yang tidak menerapkan pola Singleton dan berhati-hati bahwa Anda hanya meneruskan instance itu ke instance lain yang membutuhkannya. Di sisi lain, Singleton, dengan huruf kapital "S" adalah implementasi dari pola klasik (anti-). Pada dasarnya global yang menyamar yang tidak banyak digunakan di dunia PHP. Saya belum melihat satu sampai saat ini. Jika Anda ingin koneksi DB tunggal digunakan oleh semua kelas Anda lebih baik melakukannya seperti ini:
$db = new DbConnection;
$users = new UserCollection($db);
$posts = new PostCollection($db);
$comments = new CommentsCollection($db);
Dengan melakukan hal di atas, jelas bahwa kita memiliki seorang wanita lajang dan kita juga memiliki cara yang baik untuk menyuntikkan mock atau stub dalam tes kita. Mengejutkan bahwa unit test menghasilkan desain yang lebih baik. Tetapi masuk akal jika Anda berpikir bahwa tes memaksa Anda untuk berpikir tentang cara Anda menggunakan kode itu.
/**
* An example of a test using PHPUnit. The point is to see how easy it is to
* pass the UserCollection constructor an alternative implementation of
* DbCollection.
*/
class UserCollection extends PHPUnit_Framework_TestCase
{
public function testGetAllComments()
{
$mockedMethods = array('query');
$dbMock = $this->getMock('DbConnection', $mockedMethods);
$dbMock->expects($this->any())
->method('query')
->will($this->returnValue(array('John', 'George')));
$userCollection = new UserCollection($dbMock);
$allUsers = $userCollection->getAll();
$this->assertEquals(array('John', 'George'), $allUsers);
}
}
Satu-satunya situasi di mana saya akan menggunakan (dan saya telah menggunakannya untuk meniru objek prototipe JavaScript di PHP 5.3) anggota statis adalah ketika saya tahu bahwa masing-masing bidang akan memiliki nilai yang sama contoh lintas. Pada titik itu Anda dapat menggunakan properti statis dan mungkin sepasang metode pengambil / penyetel statis. Bagaimanapun, jangan lupa untuk menambahkan kemungkinan untuk menimpa anggota statis dengan anggota contoh. Misalnya Zend Framework menggunakan properti statis untuk menentukan nama kelas adaptor DB yang digunakan dalam contoh Zend_Db_Table
. Sudah beberapa saat sejak saya menggunakannya sehingga mungkin tidak lagi relevan, tapi itulah yang saya ingat.
Metode statis yang tidak berurusan dengan properti statis haruslah berfungsi. PHP memiliki fungsi dan kita harus menggunakannya.