Yanıtlar:
Bir özelliği tanımlamak diye bir şey yoktur.
Yalnızca, başlangıçta bellekte ayrılmış veri kapsayıcıları oldukları için özellikleri bildirebilirsiniz.
Öte yandan bir işlev tanımlanmadan (işlev gövdesi eksik) bildirilebilir (türler, adlar, parametreler) ve böylece soyut hale getirilebilir.
"Özet" yalnızca bir şeyin açıklandığını ancak tanımlanmadığını gösterir ve bu nedenle onu kullanmadan önce onu tanımlamanız gerekir, yoksa işe yaramaz hale gelir.
Hayır, derleyici ile bunu zorlamanın bir yolu yoktur, $tablename
değişken için çalışma zamanı kontrolleri (örneğin yapıcıda) kullanmanız gerekir , örneğin:
class Foo_Abstract {
public final function __construct(/*whatever*/) {
if(!isset($this->tablename))
throw new LogicException(get_class($this) . ' must have a $tablename');
}
}
Bunu Foo_Abstract'un tüm türetilmiş sınıfları için zorlamak için final
, geçersiz kılmayı önleyerek Foo_Abstract'un kurucusunu yapmanız gerekir .
Bunun yerine soyut bir alıcı ilan edebilirsiniz:
abstract class Foo_Abstract {
abstract public function get_tablename();
}
class Foo extends Foo_Abstract {
protected $tablename = 'tablename';
public function get_tablename() {
return $this->tablename;
}
}
Özelliğin bağlamına bağlı olarak, bir alt nesnede soyut bir nesne özelliğinin bildirimini zorlamak istersem static
, soyut nesne yapıcısı veya ayarlayıcı / alıcı yöntemlerinde özellik için anahtar kelimeyle bir sabit kullanmayı tercih ederim . final
Yöntemin genişletilmiş sınıflarda geçersiz kılınmasını önlemek için isteğe bağlı olarak kullanabilirsiniz .
Bunun dışında alt nesne, yeniden tanımlanırsa üst nesne özelliğini ve yöntemlerini geçersiz kılar. Örneğin, bir özellik üstteki gibi bildirilirse protected
ve alt öğe olarak yeniden tanımlanırsa public
, ortaya çıkan özellik geneldir. Ancak, mülk private
ebeveynde beyan edilirse kalır private
ve çocuk için mevcut olmaz.
http://www.php.net//manual/en/language.oop5.static.php
abstract class AbstractFoo
{
public $bar;
final public function __construct()
{
$this->bar = static::BAR;
}
}
class Foo extends AbstractFoo
{
//const BAR = 'foobar';
}
$foo = new Foo; //Fatal Error: Undefined class constant 'BAR' (uncomment const BAR = 'foobar';)
echo $foo->bar;
Yukarıda belirtildiği gibi, böyle kesin bir tanım yoktur. Bununla birlikte, alt sınıfı "soyut" özelliği tanımlamaya zorlamak için bu basit geçici çözümü kullanıyorum:
abstract class Father
{
public $name;
abstract protected function setName(); // now every child class must declare this
// function and thus declare the property
public function __construct()
{
$this->setName();
}
}
class Son extends Father
{
protected function setName()
{
$this->name = "son";
}
function __construct(){
parent::__construct();
}
}
static
mülklerle ilgili sorunu çözmüyor .
the only "safe" methods to have in a constructor are private and/or final ones
, benim geçici çözümüm böyle bir durum değil mi? içinde özel kullanıyorum
$name
. setName()
İşlevi gerçekten ayarlamadan uygulayabilirsiniz $name
.
getName
yerine kullanmanın $name
daha iyi olduğunu düşünüyorum . abstract class Father { abstract protected function getName(); public function foo(){ echo $this->getName();} }
Bugün kendime aynı soruyu sordum ve iki sentimi de eklemek istiyorum.
abstract
Özellikleri istememizin nedeni , alt sınıfların onları tanımladığından emin olmak ve olmadıklarında istisnalar atmaktır. Benim özel durumumda, static
müttefikle çalışabilecek bir şeye ihtiyacım vardı .
İdeal olarak şöyle bir şey isterim:
abstract class A {
abstract protected static $prop;
}
class B extends A {
protected static $prop = 'B prop'; // $prop defined, B loads successfully
}
class C extends A {
// throws an exception when loading C for the first time because $prop
// is not defined.
}
Bu uygulamayı bitirdim
abstract class A
{
// no $prop definition in A!
public static final function getProp()
{
return static::$prop;
}
}
class B extends A
{
protected static $prop = 'B prop';
}
class C extends A
{
}
Gördüğünüz gibi içinde A
tanımlamıyorum $prop
, ama onu bir static
alıcıda kullanıyorum. Bu nedenle, aşağıdaki kod çalışır
B::getProp();
// => 'B prop'
$b = new B();
$b->getProp();
// => 'B prop'
Öte C
yandan, ben tanımlamıyorum $prop
, bu yüzden istisnalar alıyorum:
C::getProp();
// => Exception!
$c = new C();
$c->getProp();
// => Exception!
İstisnayı getProp()
elde etmek için yöntemi çağırmalıyım ve bunu sınıf yüklemesinde alamıyorum, ancak en azından benim durumumda istenen davranışa oldukça yakın.
Zeki bir adamın (diğer bir deyişle 6 ay içinde kendimden) bunu yapmaktan kaçınmak için tanımlıyorum getProp()
.final
class D extends A {
public static function getProp() {
// really smart
}
}
D::getProp();
// => no exception...
Sadece kodunuzu test ederek öğrenebileceğiniz gibi:
Önemli hata: Özellikler 3. satırda ... satırında soyut olarak bildirilemez
Hayır yok. PHP'de özellikler soyut olarak bildirilemez.
Bununla birlikte, bir alıcı / ayarlayıcı işlev özeti uygulayabilirsiniz, aradığınız şey bu olabilir.
Mülkler uygulanmaz (özellikle kamu mülkleri), sadece vardırlar (veya yoktur):
$foo = new Foo;
$foo->publicProperty = 'Bar';
Soyut özelliklere duyulan ihtiyaç, tasarım sorunlarını gösterebilir. Yanıtların çoğu, bir tür Şablon yöntemi modeli uygularken ve işe yarasa da, her zaman biraz garip görünür.
Orijinal örneğe bir göz atalım:
abstract class Foo_Abstract {
abstract public $tablename;
}
class Foo extends Foo_Abstract {
//Foo must 'implement' $property
public $tablename = 'users';
}
Bir şeyi işaretlemek abstract
, ona sahip olunması gereken bir şeyi belirtmektir. Eh, bir olmazsa olmaz değeri (bu durumda) o işlem yaptığı yapıcı iletilmesi gereken böylece gerekli bir bağımlılık vardır :
class Table
{
private $name;
public function __construct(string $name)
{
$this->name = $name;
}
public function name(): string
{
return $this->name;
}
}
O zaman gerçekten daha somut bir adlandırılmış sınıf istiyorsanız, şu şekilde miras alabilirsiniz:
final class UsersTable extends Table
{
public function __construct()
{
parent::__construct('users');
}
}
DI kapsayıcı kullanıyorsanız ve farklı nesneler için farklı tablolar iletmeniz gerekiyorsa bu yararlı olabilir.
PHP 7, soyut "özellikler" oluşturmayı oldukça kolaylaştırır. Yukarıda olduğu gibi, bunları soyut işlevler oluşturarak yapacaksınız, ancak PHP 7 ile bu işlev için dönüş türünü tanımlayabilirsiniz, bu da herkesin genişletebileceği bir temel sınıf oluştururken işleri çok daha kolay hale getirir.
<?php
abstract class FooBase {
abstract public function FooProp(): string;
abstract public function BarProp(): BarClass;
public function foo() {
return $this->FooProp();
}
public function bar() {
return $this->BarProp()->name();
}
}
class BarClass {
public function name() {
return 'Bar!';
}
}
class FooClass extends FooBase {
public function FooProp(): string {
return 'Foo!';
}
public function BarProp(): BarClass {
// This would not work:
// return 'not working';
// But this will!
return new BarClass();
}
}
$test = new FooClass();
echo $test->foo() . PHP_EOL;
echo $test->bar() . PHP_EOL;
tablename değeri nesnenin ömrü boyunca asla değişmeyecekse, aşağıdaki basit ama güvenli bir uygulama olacaktır.
abstract class Foo_Abstract {
abstract protected function getTablename();
public function showTableName()
{
echo 'my table name is '.$this->getTablename();
}
}
class Foo extends Foo_Abstract {
//Foo must 'implement' getTablename()
protected function getTablename()
{
return 'users';
}
}
Buradaki anahtar, 'users' dize değerinin alt sınıf uygulamasında doğrudan getTablename () içinde belirtilmesi ve döndürülmesidir. İşlev "salt okunur" bir özelliği taklit eder.
Bu, daha önce ek bir değişken kullanan bir çözüme oldukça benzer. Biraz daha karmaşık olsa da Marco'nun çözümünü de beğeniyorum.