Abstract anahtar sözcüğü üzerinden PHP Statik sınıflar?

10 Cevap php

PHP manual göre, bu gibi bir sınıf:

abstract class Example {}

örneği olamaz. Örneğin ben olmadan bir sınıf gerekiyorsa, örneğin bir kayıt deseni için:

class Registry {}
// and later:
echo Registry::$someValue;

sadece soyut olarak sınıf bildirmek için iyi bir tarz olarak kabul edilebilir mi? Değilse, soyut sınıfına göre korumalı yöntem olarak kurucu gizleme avantajları nelerdir?

Rationale for asking: Bildiğim kadarıyla ben gördüğünüz gibi, elinden özellik kötüye biraz daha manuel olarak örnekleme imkanı ile daha sonra sınıfları için planları gibi soyut sınıflar anlamına gelir beri.

Update: Öncelikle, tüm cevaplar için teşekkürler! 'Sen bir soyut sınıf örneğini değil, ancak bir kayıt için, neden bir tek deseni kullanarak değil?' Fakat birçok cevaplar oldukça hem ses

Ne yazık ki, daha fazla veya daha az tam olarak sorumun bir tekrarı oldu. advantage bir singleton deseni sadece abstract bildirerek ve bu konuda endişelenmenize gerek kalmadan karşılaştırıldığında (aka __construct() gizleme) kullanarak nedir? (Gibi, örneğin, bu abstract sınıfları aslında used ya da olmadığını, geliştiriciler arasında güçlü bir çağrışım.)

10 Cevap

Sınıf bazı süper-tipi tanımlamak anlamına değilse, o abstract , derim olarak ilan edilmemelidir.

Senin durumunda, ben daha çok bir sınıf ile gitmek istiyorum:

  • That defines __construct and __clone as private methods
    • yani sınıf dışından instanciated edilemez
  • And, this way, your class could create an instance of itself


Now, why use a Singleton, and not only static methods ? I suppose that, at least a couple of reasons can be valid :

  • Singleton'ununu kullanarak sınıfının bir örneğini kullanarak anlamına gelir; sadece __construct yapmak zorunda ve __clone özel ve bazı getInstance yöntemi ekleyin: daha kolay bir singleton tek bir tek sigara sınıfını dönüştürmek için yapar.
  • Singleton'ununu kullanmak da normal bir örneği ile kullanabileceğiniz her şeyi erişim anlamına gelir: $this, özellikleri, ...
  • Oh, a third one (not sure about that, but might have its importance) : with PHP < 5.3, you have less possibilities with static methods/data :
  • Late Static Binding sadece PHP 5.3 ile eklenmiş; ve statik yöntemleri / sınıfları ile çalışırken sık sık, zor yapar sahip değil; devralmayı kullanarak özellikle.


This being said, yes, some code like this :

abstract class MyClass {
    protected static $data;
    public static function setA($a) {
        self::$data['a'] = $a;
    }
    public static function getA() {
        return self::$data['a'];
    }
}

MyClass::setA(20);
var_dump(MyClass::getA());

Çalışacak ... Ama oldukça doğal gelmiyor ... ve bu çok basit bir örnek (see what I said earlier with Late Static Binding, and magic methods).

Ne tarif PHP dili ile izin verilen, ancak bir abstract sınıfının kullanım amacı değil. Ben bir abstract sınıfının static yöntemlerini kullanmak olmaz.

İşte o yapmanın dezavantajı bulunuyor: Başka bir geliştirici kaçınmak istediğiniz ne olduğu, soyut sınıfını genişletir ve daha sonra bir nesne örneğini olabilir. Örnek:

class MyRegistry extends AbstractRegistry { }
$reg = new MyRegistry();

Doğru, amaçlanan kullanıma uygun olmayan başka bir geliştirici için soyut sınıfını teslim eğer sadece bu konuda endişelenmenize gerek, ama çok sınıf bir singleton yapmak neden budur. Işbirliği yapmayan bir geliştirici özel bir kurucu kılabilirsiniz:

class Registry
{
  private function __construct() { }
}

class MyRegistry extends Registry
{
  public function __construct() { } // change private to public
}

Bu sınıf kendiniz kullanarak olsaydı, sadece not sınıf örneğini unutmayın olacaktır. Sonra bunu önlemek için ya mekanizmasına ihtiyaç olmazdı. Eğer başkaları tarafından kullanılmak üzere bu tasarlarken beri Yani, sizin amaçlanan kullanımını engellemeyi gelen bu insanları engellemek için bir yol gerekir.

Yani bu iki olası alternatifleri sunuyoruz:

  1. Tekiz desen sopa ve emin kurucu de final hiç kimse sınıfını genişletir ve non-private kurucu değiştirebilirsiniz olduğundan emin olun:

    class Registry
    {
      private final function __construct() {
      }
    }
    
  2. Registry desteği both, statik ve nesne kullanımı olun:

    class Registry
    {
      protected static $reg = null;
    
    
      public static function getInstance() {
        if (self::$reg === null) {
          self::$reg = new Registry();
        }
        return self::$reg;
      }
    }
    

    Sonra statik Registry::getInstance() arayabilir, ya da bir nesne örneği isterseniz new Registry() arayabilirsiniz.

    Sonra global kayıt içinde yeni bir kayıt defteri örneğini saklamak gibi şık şeyler yapabilirsiniz! :-)

    I Zend_Registry , Zend Framework bir parçası olarak bu uygulamaya

Diğer çocuklar dediği gibi, soyut bir sınıf başlatamazsınız. Sen başlatmasını önlemek için sınıfındaki statik yöntemleri kullanabilirsiniz, ama ben düzgün bir sebep yoksa ben gerçekten bunu yaparken bir hayranı değilim.

Ben şimdi biraz konu dışı olabilir, ama sizin örnekte size Defteri desen sınıfı için bu istediğini söyledi. Bunu örneğini istemiyorum sebebi nedir? Öyle değil daha iyi kullanmak istediğiniz her kayıt için Registry bir örneğini oluşturmak için?

Gibi bir şey:

class Registry {
    private $_objects = array( );

    public function set( $name, $object ) {
        $this->_objects[ $name ] = $object;
    }

    public function get( $name ) {
        return $this->_objects[ $name ];
    }
}

Hatta bu durumda Singleton kullanmak olmaz.

Sadece statik özellikleri / yöntemleri tanımlayan soyut bir sınıf ayarlama gerçek bir etkisi olmaz. Sen, sınıfını genişleten örnekleriz, ve bunun üzerine bir yöntemini çağırın ve statik sınıf özelliklerini değiştirmek istiyorsunuz olabilir. Açıkçası çok kafa karıştırıcı.

Soyut da yanıltıcıdır. Soyut bazı işlevleri uygulayan bir sınıf tanımlamak için ment, ancak düzgün çalışması için (miras yoluyla eklenmiştir) daha fazla davranış ihtiyacı var. Genellikle tüm statik birlikte kullanılmamalıdır bir özellik olduğunu üstüne. Bunu pratikte yanlış kullanmak için programcılar davet ediyoruz.

Kısa cevap: Özel bir yapıcı daha anlamlı olması ve güvenli başarısız olur.

Yaygın ve tanınan OO desenler vardır. abstract sıradışı bir şekilde kullanılması karışıklığa neden (üzgünüm, benim bazı örnekler yerine PHP Java edilir):

  • abstract class - a class meant to conceptualize a common ancestor, but of which actual instances are not meant to exist (e.g. shape is an abstract superclass for rectangle and triangle).
    Commonly implemented by:
    • doğrudan Destekleme önlemek için sınıf abstract değiştirici kullanmak, ancak sınıfından türetmek izin
  • utility class - a class that does not represent an object in the solution space, but rather is a collection of useful static operations/methods, e.g. Math class in Java.
    Commonly implemented by:
    • sınıf örneğin, non-derive yapmak Java sınıf final değiştirici kullanır ve
    • doğrudan Destekleme önlemek - oluşturucusu yok sağlamak ve herhangi bir örtük veya varsayılan Kurucular (ve kopya kurucular) gizleme veya devre dışı bırakmak
  • singleton class - a class that does represent an object in the solution space, but whose instantiation is controlled or limited, often to insure there is only one instance.
    Commonly implemented by:
    • sınıf örneğin, non-derive yapmak Java sınıf final değiştirici kullanır ve
    • Hiçbir kurucular sağlamak ve herhangi bir örtük veya varsayılan Kurucular (ve kopya kurucular) gizlemek veya devre dışı bırakmak, ve - doğrudan Destekleme önlemek
    • statik bir yöntem (genellikle getInstance()) örneklerinin sınırlı sayıda, sadece örneği veya birini verir - bir örneğini elde etmek için özel bir yol sağlar

abstract gerçekten sınıf kalıtım için, onu aramak gibi, bir "plan" göstermek içindir.

Sicilleri genelde bir özel değişkene kendini örneğini kalacak anlamına gelir bir tek desen uygulayın. Olarak tanımlanması abstract bu çalışmasını engeller olacaktır.

Ben soyut bir sınıf kullanmak olmaz. Eğer önermek gibi id korumalı özel / kurucu ile bir singleton daha benzer bir şey kullanın. $instance, hangi gerçek kayıt örneği dışında çok az statik özellikler olmalıdır. Son zamanlarda ive böyle bir şeydir Zend Altyapıları tipik desen hayranı olmak:

class MyRegistry {

  protected static $instance = null;

  public function __construct($options = null)
  {
  }

  public static function setInstance(MyRegistry $instance)
  {
    self::$instance = $instance;
  }

  public static function getInstance()
  {
     if(null === self::$instance) {
        self::$instance = new self;
     }

     return self::$instance;
  }
}

Bu şekilde aslında singleton'ununu olsun ama kullanmak üzere yapılandırılmış bir örneğini enjekte edebilir. Bu test amaçlı ve miras için kullanışlıdır.

Soyut bir sınıf amacı diğer sınıflara 1) anlamlı ve zaman değil, bu sınıflardan birinin bağlamında 2) anlamlı olmayan yöntemleri tanımlamaktır.

Php dokümanlar bazı Parafaz için, bir veritabanına bağlanırken hayal. Eğer bağlanmak için veritabanı belli bir tür yoksa bir veritabanına bağlanma pek mantıklı değil. Yine bağlantı ne olursa olsun veritabanı tür yapmak istediğiniz bir şeydir. Bu nedenle, bağlantı soyut bir veritabanı sınıfında tanımlanmış ve miras, ve bir MYSQL sınıfın, diyelim ki, tarafından anlamlı yapılabilir.

Bunu yapmak niyetinde ama bunun yerine sadece bir örneği olmayan bir sınıf gerekmez gibi gereksinimleri, bu sesler. Eğer bu davranışı uygulamak için soyut bir sınıf kullanabilirsiniz iken, bu benim için hacky görünüyor kötüye kullanmakta soyut sınıfların amacı çünkü. Ben bir soyut sınıf karşılaşırsanız, ben makul bu, örneğin, bazı soyut yöntem olacağını beklemek gerekir, ancak sınıf hiçbiri olacaktır.

Bu nedenle, bir tek daha iyi bir seçenek gibi görünüyor.

Ancak, her yerde onu aramak böylece bir örneği olmayan bir sınıf var isteyen nedeni basitçe ise o zaman neden bile hiç bir sınıf var mı? Neden sadece bir küresel olarak her değişken yük değil ve o zaman sadece sınıfı aracılığıyla doğrudan ziyade diyebilirsin?

Bunu yapmak için en iyi yolu, sınıf örneğini ve sonra bağımlılık enjeksiyon ile etrafında geçmek olduğunu düşünüyorum. Bunu yapmak için çok tembel ise (ve yeterince adil eğer sen! Onun kod, benim değil.) Sonra tüm sınıf ile rahatsız etmeyin.

Hızlı şeyler yapmak ihtiyacı ve bazı şeyleri doğru şekilde yapmak için ihtiyacı: Eğer 2 ihtiyaçları arasındaki çatışma gibi UPDATE: görünüyor. Kendinize zaman tasarrufu uğruna global değişkenler bir ton taşıma umurumda değil ise, güya daha az yazmaya içerir çünkü bir singleton üzerinde soyut kullanmayı tercih edecektir. Sizin için daha önemli olan ihtiyaç almak ve sopa ile.

Burada doğru yolu Singleton veya soyut bir sınıf kullanmak yerine bağımlılık enjeksiyon kullanmak için değil kesinlikle. Hızlı bir şekilde globalsin bir ton ya da soyut bir sınıf sahip olmaktır.

Sınıfların tamamı (ve tek) amacı yeni nesneler için planları olarak hizmet etmektir çünkü benim anlayış, örneği olmayan bir sınıf, bir OOP programda kullanarak olmamalıdır şeydir. Registry::$someValue ve $GLOBALS['Registry_someValue'] eski görünüyor 'meraklısı', ama ne yol gerçekten nesne yönelimli olmasıdır arasındaki tek fark.

Yani, soru cevap, size isteğe bağlı olarak bir fabrika yöntemi ile donatılmış bir tek nesne, istediğiniz, bir "tek sınıf" istemiyorum:

class Registry
{
    static $obj = null;

    protected function __construct() {
        ...
    }

    static function object() {
        return self::$obj ? self::$obj : self::$obj = new self;
    }
}

...

Registry::object()->someValue;

Açıkça abstract burada çalışmaz.

Ben kodlama habbits meselesi olduğunu söyleyebilirim. Eğer soyut bir sınıf düşündüğümüz zaman genellikle kullanmak için alt sınıf gereken bir şeydir. Yani sınıf özetini ilan karşı sezgisel.

Eğer soyut yaparsanız Bunun dışında oldukça $ daha, sadece yöntemleri self :: $ someVar kullanarak bir konudur bu-> SomeVar bir singleton olarak uygulamak durumunda.