Örneği sınıfları vs statik ne zaman kullanılır

9 Cevap php

PHP benim ilk programlama dilidir. Örneği nesneler vs statik sınıflar ne zaman kullanılacağı oldukça etrafında başımı sarmak olamaz.

Ben nesneleri çoğaltabilirsiniz ve klon biliyoruz. Ancak php kullanarak benim her an herhangi bir nesne veya işlev her zaman tek bir geri dönüş (dizi, string, int) değer ya da boşluk olarak sona erdi.

Ben bir video oyunu karakteri sınıfında gibi kitaplar kavramları anlamak. duplicate car object and make the new one red, tüm mantıklı, ama php ve web uygulamaları uygulama nedir gelmez.

Basit bir örnek. Bir blog. Bir blogun ne nesneleri iyi statik veya örneği nesneler olarak uygulanacak olurdu? DB sınıf? Neden sadece küresel kapsamda db nesne örneğini değil? Yerine neden her nesne statik yapmak değil mi? Ne performansı hakkında?

Hepsi sadece stil mi? Bu şeyler yapmak için uygun bir yolu var mı?

9 Cevap

Bu oldukça ilginç bir soru - cevap ^ ^ çok ilginç alabilirsiniz

Şeyleri dikkate almak basit yolu olabilir:

  • her nesne kendi verilerine sahip (bir kullanıcı gibi bir ismi var) bir instanciated sınıfını kullanın
  • diğer şeyler üzerinde çalışan sadece bir araç ne zaman statik bir sınıf kullanabilirsiniz (örneğin gibi, HTML BB kodu için bir sözdizimi dönüştürücü, o kendi başına bir hayat yok)

(Yeah, I admit, really really overly-simplified...)

Statik yöntemler / sınıflar hakkında bir şey (de en azından PHP, ama muhtemelen diğer dillerde) birim test kolaylaştırmak kalmamasıdır.

Eğer bir yerde bir değere bazı Sınıfım :: $ mydata ayarlarsanız, bu değere sahip olacak, ve sadece, her yerde - kullanıcı hakkında konuşan: statik veri hakkında başka bir şey bunun sadece bir örneği programınızda var olduğunu Eğer sadece tek bir kullanıcı varsa mümkün olacaktır - yani büyük değil, değil mi?

Bir blog sistem için, ben ne diyebilirim? Ben gibi statik yazardım çok şey yok aslında, sanırım; belki DB erişim sınıfı, ama muhtemelen, sonunda ^ ^

Statik yöntemler kullanarak karşı iki ana nedeni vardır:

  • Statik yöntemler kullanarak kodu test zordur
  • Statik yöntemler kullanarak kodu extend zordur

Diğer bazı yöntem içinde statik bir yöntem çağrısı sahip global bir değişken içe aslında daha kötüdür. PHP, sınıflar yüzden her zaman küresel bir sembol (sınıf adı) güveniyor statik bir yöntem aramak, küresel semboller vardır. Küresel kötü olduğunda bu bir durumdur. Ben Zend Framework bazı bileşeni ile yaklaşım, bu tür sorunları vardı. Nesneleri oluşturmak için statik yöntem çağrıları (fabrikalar) kullanmak sınıfları vardır. Bana özel bir nesne geri almak için bu örneği başka bir fabrika tedarik imkansız oldu. Bu sorunun çözümü ancak örneklerini ve instace yöntemleri kullanın ve programın başında singletons ve benzeri zorlamaktır.

Miško Hevery, Google'da bir Çevik Antrenör olarak çalışan kim, biz nesneyi kullanmak zaman nesne oluşturma zaman ayırmak gerektiğini, ilginç bir teorisi var, ya da daha doğrusu tavsiye ederiz. Yani bir programın yaşam döngüsü ikiye bölünür. Uygulama ve fiili çalışır kesiminde tüm nesne kablolama önemser ilk bölümü (main() yöntemi diyelim).

Yani yerine sahip:

class HttpClient
{
    public function request()
    {
        return HttpResponse::build();
    }
}

Biz oldukça yapmalıyız:

class HttpClient
{
    private $httpResponseFactory;

    public function __construct($httpResponseFactory)
    {
        $this->httpResponseFactory = $httpResponseFactory;
    }

    public function request()
    {
        return $this->httpResponseFactory->build();
    }
}

Ve sonra, dizin / ana sayfasında, biz (bu nesne kablolama adım, ya da program tarafından kullanılacak örnekleri grafik oluşturmak için zamanı) yapardım:

$httpResponseFactory = new HttpResponseFactory;
$httpClient          = new HttpClient($httpResponseFactory);
$httpResponse        = $httpClient->request();

Ana fikir, sınıfların dışında bağımlılıkları decouple etmektir. Bu şekilde kod çok daha genişletilebilir ve benim için en önemli parçası, test edilebilir. Neden sınanabilir olması daha önemlidir? Ben hep kütüphane kod yazmak istemiyorum, bu yüzden genişletilebilirlik o kadar önemli değil, ama ben üstlenmeden yaptığınızda testability önemlidir çünkü. Her neyse, sınanabilir kodu genellikle genişletilebilir kod verir, bu yüzden gerçekten bir ya-ya da durum değil.

Miško Hevery de (veya sermaye S olmadan) tekiz Singletons arasında net bir ayrım yapar. Fark çok basittir. Düşük bir durumda "s" ile Singletons ana endeksinde / de kablo yürütür. Sen not Singleton deseni uygulamak ve sadece ihtiyacı herhangi bir diğer örneği bu örneği geçmek dikkat etmez, bir sınıfın bir nesne örneğini. Öte yandan, bir sermaye "S" ile Singleton, klasik (anti-) desen bir uygulamasıdır. PHP dünyada çok kullanıma sahip olmadığı kılık temelde küresel bir. Ben bu noktaya kadar birini görmedim. İsterseniz tüm sınıfları tarafından kullanılacak bir tek DB bağlantı gibi bunu yapmak daha iyidir:

$db = new DbConnection;

$users    = new UserCollection($db);
$posts    = new PostCollection($db);
$comments = new CommentsCollection($db);

Yukarıdaki yaparak biz singleton'ununu var ve biz de testlerde bir mock veya bir taslaktır enjekte etmek için güzel bir yol olduğu açıktır. Bu ünite testleri daha iyi bir tasarım yol nasıl şaşırtıcı bulunuyor. Eğer testler bu kodu kullanmak istiyorum yol hakkında düşünmeye zorlar düşünüyorum ama ne zaman bu anlamda çok yapar.

/**
 * 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);
    }
}

Ben ilgili alan aynı değeri çapraz örnek olacağını biliyorum ben kullanmak istiyorum (ve PHP 5.3 JavaScript prototip nesnesi taklit etmek için onları kullandım) statik üyeleri tek durumdur. Bu noktada statik bir özellik ve belki statik alıcı / ayarlayıcı yöntemleri bir çift kullanabilirsiniz. Neyse, bir örneği üyesi ile statik üyesi geçersiz için olasılığı eklemek için unutmayın. Örneğin Zend Framework Zend_Db_Table örneklerini kullanılan DB adaptör sınıfın adını belirtmek için bir statik özelliğini kullanarak edildi. Bu artık alakalı olabilir bu yüzden ben onları kullandım beri süre oldu, ama ben hatırlıyorum nasıl oluyor.

Statik özellikleri ile anlaşma yok Statik yöntemler fonksiyonları olmalıdır. PHP fonksiyonları vardır ve biz bunları kullanmak gerekir.

Yani PHP statik işlevleri veya değişkenlere uygulanabilir. Olmayan statik değişkenler bir sınıf belirli bir örneğe bağlı. Statik olmayan yöntemler bir sınıf örneğine hareket. Yani adında bir sınıf yapalım BlogPost.

title, bir statik olmayan üye olacaktır. O blog yazısı unvanını içerir. Ayrıca adı verilen bir yöntem olabilir find_related(). Bu blog yazısı sınıfının belirli bir örneği bilgi gerektirir, çünkü statik değil.

Bu sınıf, bu gibi bir şey olacaktır:

class blog_post {
    public $title;
    public $my_dao;

    public function find_related() {
        $this->my_dao->find_all_with_title_words($this->title);
    }
}

Öte yandan, statik fonksiyonları kullanarak, böyle bir sınıf yazmak olabilir:

class blog_post_helper {
    public static function find_related($blog_post) {
         // Do stuff.
    }
}

Fonksiyonu statik ve herhangi bir blog yazısı hareket değil çünkü bu durumda, bir argüman olarak blog yazısı geçmelidir.

Temelde bu nesne yönelimli tasarım hakkında bir soru. Sizin sınıfları sisteminde isimler vardır ve bunların hareket işlevleri fiiller vardır. Statik işlevleri usul vardır. Bağımsız değişken olarak fonksiyonları nesne geçer.


Güncelleme: Ben de kararın örnek yöntemleri ve statik yöntemler arasında nadiren olduğunu ve daha eklemek sınıflarını kullanarak ve ilişkisel diziler kullanarak arasındaki ediyorum. Örneğin, bir blog uygulaması, size veritabanından blog yazılarını okumak ya ve nesneler haline dönüştürmek, ya da set sonuç onları bırakın ve ilişkisel diziler gibi davranın. Sonra argüman olarak ilişkilendirilebilir dizilerin ilişkilendirilebilir diziler veya listeleri çekmek fonksiyonları yazmak.

OO senaryoda, bireysel mesajların hareket sizin BlogPost sınıfının yöntemlerini yazmak ve mesajların koleksiyonları hareket statik yöntemleri yazmak.

Hepsi sadece stil mi?

Uzun bir yol, evet. Hiç statik üyeleri kullanmadan gayet iyi bir nesne yönelimli programlar yazabilirsiniz. Aslında bazı insanlar statik üyeleri ilk etapta bir kirlilik olduğunu iddia ediyorum. Ben öneririm - oop bir acemi gibi - hep birlikte statik üyeleri önlemek için deneyin. Bir object oriented yerine procedural tarzında yazma yönünde sizi zorlar.

Öncelikle kendinize sorun, ne bu nesnenin temsil edecek? Bir nesne örneği dinamik veri ayrı kümeleri üzerinde çalışan için iyidir.

Iyi bir örnek ORM veya veritabanı soyutlama katmanı olacaktır. Birden fazla veritabanı bağlantıları olabilir.

$db1 = new Db(array('host' => $host1, 'username' => $username1, 'password' => $password1));
$db2 = new Db(array('host' => $host2, 'username' => $username2, 'password' => $password2));

Bu iki bağlantıları şimdi bağımsız çalışabilir:

$someRecordsFromDb1 = $db1->getRows($selectStatement);
$someRecordsFromDb2 = $db2->getRows($selectStatement);

Şimdi bu paket / kütüphane içerisinde, bir SELECT deyimi döndürüldü belirli bir satırı temsil etmek vb Db_Row gibi diğer sınıflar olabilir. Bu Db_Row sınıf statik bir sınıf olsaydı, o zaman tek bir veritabanında bir satır veri var ve bir nesne örneği olabilir yapmak imkansız olacağını varsayarak olacaktır. Bir örnek ile, artık veritabanları sınırsız sayıda tablolar sınırsız sayıda satır sınırsız sayıda olabilir. Tek sınır sunucu donanım ;) olduğunu.

Db nesne üzerinde GetRows yöntem Db_Row nesneleri dizisini döndürür Örneğin, artık birbirinden bağımsız olarak her satırda üzerinde çalışabilir:

foreach ($someRecordsFromDb1 as $row) {
    // change some values
    $row->someFieldValue = 'I am the value for someFieldValue';
    $row->anotherDbField = 1;

    // now save that record/row
    $row->save();
}

foreach ($someRecordsFromDb2 as $row) {
    // delete a row
    $row->delete();
}

Statik bir sınıfın iyi bir örnek yalnızca bir kayıt ya da kullanıcı başına bir oturum olacak beri kayıt değişkenlerini veya oturum değişkenleri kolları şey olurdu.

Başvurunuzun bir bölümünde:

Session::set('someVar', 'toThisValue');

Ve başka bir bölümünde:

Session::get('someVar'); // returns 'toThisValue'

Sadece hiç oturum başına bir seferde bir kullanıcı olmak için oraya gidiyor beri, Oturumu'nda bir örneğini oluşturmaya hiçbir nokta yoktur.

Ben bu net şeyler yardımcı olmak için diğer cevapları ile birlikte, yardımcı olur umarım. Bir yan not olarak, "cohesion" check out ve "coupling". Onlar tüm programlama dilleri için geçerli kodunuzu yazarken kullanmak için bazı çok, çok iyi uygulamaları içermektedir.

Kesinlikle bir singleton oluştururken sürece tüm örnekleri veya arasında paylaşılacak sürece genel olarak, üye değişkenleri ve üye işlevleri kullanmanız gerekir. Sadece statik veri ve işlevleri kullanmak eğer faaliyet verilerin bir kopyasını olabilir oysa üye veri ve üye fonksiyonlarını kullanarak, veri birden fazla farklı parçaları için fonksiyonlarınızı yeniden sağlar. PHP olarak geçerli olmasa sınıf veri katılışlılığı kolaylaştırır oysa Ayrıca, statik fonksiyonları ve veri, evresel olmayan olmanın kod yol.

"Diğer bazı yöntem içinde bir statik yöntem çağrısı sahip global bir değişken içe aslında daha kötüdür." "Statik özellikleri ile anlaşma yok Statik yöntemler fonksiyonları olmalıdır" ("kötü" tanımlamak) ... ve.

Bunlar hem oldukça kapsamlı ifadelerdir. Ben konu ilişkili olan fonksiyonları bir dizi var, ancak örnek veri tamamen uygunsuz ise, ben daha ziyade onları genel ad onları her bir sınıfta tanımlı değil olurdu. Ben sadece PHP5 mevcut mekaniği kullanıyorum

  • Herhangi bir isim çatışmalar kaçınarak - hepsini bir ad vermek
  • fiziksel yerine projeye dağılmış olma arada yer tutmak - diğer geliştiricilerin daha kolay zaten mevcut olanı bulmak ve yeniden icat tekerlek daha az olasıdır olabilir
  • bana herhangi bir sihirli değerleri için sınıf consts yerine küresel tanımlar kullanmasına izin

sadece tamamen yüksek uyum ve düşük kavrama uygulamak için uygun bir yoldur.

Ve FWIW - yok böyle bir şey "statik sınıflar" olarak, en azından PHP5'ta vardır; yöntemleri ve özellikleri statik olabilir. Sınıfın Destekleme önlemek için, bir de, soyut ilan edebilir.

Sınıf (mümkünse hiçbir örneği olmadığı için) diğer sınıflara etrafında nesneyi geçmek anlamına gelir ki statik böylece tüm sınıfları doğrudan kod anlamına gelir statik sınıf şimdi sıkı sınıf ile birleştiğinde olduğunu kullanıyor olacak demektir .

Sıkı bağlama kodunuzu daha az, yeniden kırılgan ve hata eğilimli kılar. Diğer sınıflara sınıf örneğini geçmek edebilmek için statik sınıflar önlemek istiyor.

Ve evet bu sadece bir zaten söz edilmiştir bazıları bir çok nedenlerden biridir.

I'd like to say that there is definitely a case where I'd like static variables- in cross-language applications. You could have a class that you pass a language to (e.g. $_SESSION['language']) and it in turn accesses other classes that are designed like so:

Srings.php //The main class to access
StringsENUS.php  //English/US 
StringsESAR.php  //Spanish/Argentina
//...etc

Strings :: getString ("somestring") kullanarak uygulama dışında soyut dil kullanımı için güzel bir yoldur. Sen ancak lütfen ama bu durumda her dizeleri dosya Dizeler sınıfı tarafından erişilen dize değerleri ile sabitleri var olan oldukça iyi çalışıyor bunu yapabilirdi.