Statik yöntemleri kullanmaya karşı başlıca iki neden:
- statik yöntemler kullanarak kod test etmek zordur
- statik yöntemler kullanarak kodun genişletilmesi zordur
Statik bir yöntem çağrısının başka bir yöntemin içinde olması, genel bir değişkeni içe aktarmaktan daha kötüdür. PHP'de sınıflar genel sembollerdir, dolayısıyla statik bir yöntemi her çağırdığınızda genel bir sembole (sınıf adı) güvenirsiniz. Küresel kötülüğün olduğu bir durum bu. Zend Framework'ün bazı bileşenlerinde bu tür bir yaklaşımla sorunlar yaşadım. Nesneleri oluşturmak için statik yöntem çağrıları (fabrikalar) kullanan sınıflar vardır. Özelleştirilmiş bir nesnenin geri döndürülmesi için bu örneğe başka bir fabrika tedarik etmem imkansızdı. Bu sorunun çözümü, programın başında yalnızca örnek ve instagram yöntemlerini kullanmak ve tekilleri ve benzerlerini uygulamaktır.
Google'da Çevik Koç olarak çalışan Miško Hevery , ilginç bir teoriye sahiptir veya daha ziyade, nesne oluşturma zamanını nesneyi kullandığımız zamandan ayırmamız gerektiğini tavsiye eder. Yani bir programın yaşam döngüsü ikiye ayrılır. Uygulamanızdaki main()
tüm nesne kablolarını ve gerçek işi yapan kısmı ele alan ilk bölüm ( yöntem diyelim).
Yani sahip olmak yerine:
class HttpClient
{
public function request()
{
return HttpResponse::build();
}
}
Yapmayı tercih etmeliyiz:
class HttpClient
{
private $httpResponseFactory;
public function __construct($httpResponseFactory)
{
$this->httpResponseFactory = $httpResponseFactory;
}
public function request()
{
return $this->httpResponseFactory->build();
}
}
Ve sonra, indeks / ana sayfada yapardık (bu, nesne kablolama adımı veya program tarafından kullanılacak örneklerin grafiğini oluşturma zamanıdır):
$httpResponseFactory = new HttpResponseFactory;
$httpClient = new HttpClient($httpResponseFactory);
$httpResponse = $httpClient->request();
Ana fikir bağımlılıkları sınıflarınızdan ayırmaktır. Bu şekilde kod çok daha genişletilebilir ve benim için en önemli kısım test edilebilir. Test edilebilir olmak neden daha önemlidir? Her zaman kütüphane kodu yazmadım, bu nedenle genişletilebilirlik o kadar önemli değil, ancak yeniden düzenleme yaparken test edilebilirlik önemlidir. Her neyse, test edilebilir kod genellikle genişletilebilir kod verir, bu yüzden gerçekten bir ya da durum değildir.
Miško Hevery ayrıca singletons ve Singletons (büyük S ile veya büyük S olmadan) arasında net bir ayrım yapar. Aradaki fark çok basit. Küçük harfleri "s" olan tekil parametreler dizin / ana kablo tesisatı tarafından zorlanır. Sen bir sınıfın bir nesne örneğini değil Singleton deseni uygulamak ve sadece ihtiyacı başka örneğine bu örneği geçmesi dikkat ediniz. Öte yandan, Singleton, sermayesi "S" olan klasik (anti-) örüntünün bir uygulamasıdır. Temelde PHP dünyasında fazla bir kullanımı olmayan kılık değiştirmiş bir küresel. Bu noktaya kadar bir tane görmedim. Tek bir DB bağlantısının tüm sınıflarınız tarafından kullanılmasını istiyorsanız bunu şu şekilde yapmak daha iyidir:
$db = new DbConnection;
$users = new UserCollection($db);
$posts = new PostCollection($db);
$comments = new CommentsCollection($db);
Yukarıdakileri yaparak bir singletonumuz olduğu ve testlerimize bir sahte ya da saplama enjekte etmenin güzel bir yolunun olduğu açıktır. Ünite testlerinin nasıl daha iyi bir tasarıma yol açtığı şaşırtıcıdır. Ancak, testlerin sizi bu kodu kullanma şeklinizi düşünmeye zorladığını düşündüğünüzde çok mantıklıdır.
/**
* 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);
}
}
Kullanabileceğim tek durum (ve PHP 5.3'teki JavaScript prototip nesnesini taklit etmek için kullandım) statik üyeleri, ilgili alanın aynı değere sahip çapraz örneğe sahip olacağını bildiğim zamandır. Bu noktada bir statik özellik ve belki bir çift statik alıcı / ayarlayıcı yöntemi kullanabilirsiniz. Her neyse, statik üyeyi bir örnek üyeyle geçersiz kılma olasılığını eklemeyi unutmayın. Örneğin Zend Framework, örneklerinde kullanılan DB bağdaştırıcı sınıfının adını belirtmek için statik bir özellik kullanıyordu Zend_Db_Table
. Onları kullandığımdan beri bir süredir bu yüzden artık alakalı olmayabilir, ancak bu şekilde hatırlıyorum.
Statik özelliklerle ilgilenmeyen statik yöntemler işlevler olmalıdır. PHP'nin işlevleri vardır ve bunları kullanmalıyız.