Yapıcı olmayan sınıf değişkenleri başlatma zorlamak nasıl?

6 Cevap php

Ben iki sınıf vardır:

abstract Entity, abstract ClassA extends Entity, ClassB extends ClassA

Varlık gibi Otomobil veya Öğrenci gibi kuruluşlar, her türlü bir genel sınıftır. ER diyagram varlığın tam sınıf adını içeren $_entity_name adında bir statik sınıf değişken vardır.

Büyük bir sorun: Varlık, bu değişkenin değerini ayarlamak, ancak bunu kullanır olamaz! Yani must Varlık içinde tanımlamak, ama ben ClassA onu yeniden tanımlayabilirsiniz.

ClassA ("Öğrenci" diyelim) bir özel ORM işletmenin otomatik oluşturulan temel sınıftır. Kullanıcı kendi iş mantığı eklemek için bu temel sınıf alt sınıf gerekiyordu.

ClassB kullanıcı tarafından oluşturulan ve Classa uzanır. İşte o onun iş mantığını ekler yer. Ona dokunmak $_entity_name veya bu değeri ayarlamak gerekmiyor.

Gördüğüm tek yolu şudur:

ClassA makul değerlere bu "sistem seviyesinde" örnek değişkenleri başlatır init () yöntemini tanımlar.

Ben kullanıcı alışılmadık bir şey arama hakkında hiç düşünmek zorunda değil istiyorum. O explicitely zamanda ebeveyn sınıfının yapıcı veya aramak için PHP olağan olmadığını bilmiyorum. Ama değil sanırım.

Questions: A) What's the most convenient way to call init() after instantiation of the class? B) Is there a way to achieve that in such a way, that the user who creates ClassB must not think at all about calling init()? C) What other options do I have?

6 Cevap

Not exactly an answer to your question but maybe a solution for your problem:
Instead of having a property containing the actual class name (that's what you wanted, isn't it?) you can use get_called_class() (as of php 5.3.0) to get the name of the class for which the static function has been called.

 class Entity {
   public static function foo() {
     echo 'name=', get_called_class(), "\n";
   }
 }

 class ClassA extends Entity { }
 class ClassB extends ClassA { }

 Entity::foo();
 ClassA::foo();
 ClassB::foo();

baskılar

 name=Entity
 name=ClassA
 name=ClassB

Aslında parent::__construct() kullanarak ana kurucusunu çağırmak için oldukça yaygındır. Aşağıdakileri yapmanız için kabul edilebilir olurdu?

class B extends A { 
    function __construct($entity_name = '') {
        parent::__construct($entity_name);
    }
}

abstract class A extends Entity { 
    function __construct($entity_name = '') {
        parent::__construct($entity_name);
    }
}

abstract class Entity { 
    static $entity_name;
    function __construct($entity_name = '') {
        self::$entity_name = $entity_name;
    }
}

$b = new B('my_name');

Bildiğim kadarıyla sizin sorunuzu anladığım kadarıyla: Eğer ClassB o ClassA bir alt sınıfıdır ve bir ClassB nesnesi başlatıldığında, siz (bir yöntemi var istiyorum örneğin init()) kullanıcı ClassB kod bu tür bir şey yazmaya gerek kalmadan ClassA düzeyde çağrılacak.

That is what constructors are for.

Ancak, ClassB sizin kullanıcı tarafından yazılmış olacağını beri bu düşünce nedeni yüzden, sen, classB en kurucusundan parent::__construct() aramak için / onu zorlamak istemiyorum ima etti init() yöntemi kullanarak ve aynı zamanda neden olması için bir yol arıyoruz ve init() automagically yol __construct(), ben haklıyım denir edilecek? Peki, bu konuda:

  • kullanıcı o / o ClassB yazdığında aşırı gerektiğini ClassA boş init() yöntemi eklemek
  • Eğer yapmak istediğim şeyler yapmak ClassA en __construct() Classa en __construct() plus çağrı {[(4)] (örneğin $_entity_name başlatılamadı) }.
  • kullanıcı kurucu yüklenmeyin böylece final olarak ClassA bulunuyor __construct() set.
  • onlar ClassA alt sınıflarının için özel başlatma yapmak için init() yöntemi aşırı zorunda kullanıcıların söylemek

Artıları: Eğer başlatma şeyler bir şey yazmak için kullanıcıyı kalmadan ClassA ile yapmış olabilir.

Eksileri: kullanıcı aşırı olamaz __construct() ama ClassB için özel başlatma yapmak için init() yerine aşırı yüklenmeye neden olabilir

VolkerK cevabı doğru bir - ama aynı zamanda instanceof operatörü ve get_class () işlevleri bakmak olabilir.

"Ne yazık ki ER şemada PHP sınıfı, ama Varlık adını ment vermedi. Bu biraz farklı" (openfrog)

Bu ancak 2 listeleri arasında eşleme girdileri bir no-beyin (sizin varlık adlandırma sisteminde bu kusur edemem varsayarak), tamamen farklı bir sorun var.

Çalışma zamanında bir özelliğini kullanarak çözüm çok dağınık ve esnek değildir. Bu bir örtülü haritalama güvenir detayları tüm kod temeli üzerinde dağınık ve herhangi bir non-lineer sezgisel / debug korumak için çok zor olacaktır (örn. eğer ERD aynı varlık birden fazla sınıf haritalar).

C.

ClassB altında, ben ClassA başlatması sağlamak için iki yol bakın:

  1. classB yapıcı çağrıları parent::__construct() ya da yok olduğunu söyleyin.

  2. ClassA tarafından çağırılan ve ClassB tarafından uygulanan bir kanca init işlevi oluşturun. Bu şekilde, ClassA $this->init() ile __construct() ve ClassB içinde ClassA başlatma gerçekleştirir

Bu öneri, ihtiyaçlarınıza en uygun hangi geçersiz kılınamaz.

Class A{
   final public function __construct() {
       // do your stuff here

       // optionally add something like this:
       $rc = new ReflectionClass($this);
       if(in_array('init', $rc->getMethods()) {
           $this->init();
       }
   }

Ne istediğinizi yapmak değilse, sizin sınıf kapsüllenmesinde yerine devralmasını düşünmek gerekir (yani __construct() A kullanmak mümkün türeyen sınıflar istiyorum) o.