जवाबों:
किसी संपत्ति को परिभाषित करने जैसी कोई बात नहीं है।
आप केवल संपत्तियों की घोषणा कर सकते हैं क्योंकि वे आरंभीकरण पर स्मृति में आरक्षित डेटा के कंटेनर हैं।
दूसरी ओर एक फ़ंक्शन को परिभाषित किया जा सकता है (प्रकार, नाम, पैरामीटर) परिभाषित किए बिना (फ़ंक्शन बॉडी गायब) और इस प्रकार, इसे सार बनाया जा सकता है।
"सार" केवल इंगित करता है कि कुछ घोषित किया गया था लेकिन परिभाषित नहीं किया गया था और इसलिए इसका उपयोग करने से पहले, आपको इसे परिभाषित करने की आवश्यकता है या यह बेकार हो जाता है।
नहीं, यह लागू करने का कोई तरीका नहीं है कि संकलक के साथ, आपको $tablename
चर के लिए रन-टाइम चेक्स (जैसे कि कंस्ट्रक्टर में) का उपयोग करना होगा , जैसे:
class Foo_Abstract {
public final function __construct(/*whatever*/) {
if(!isset($this->tablename))
throw new LogicException(get_class($this) . ' must have a $tablename');
}
}
Foo_Abstract के सभी व्युत्पन्न वर्गों के लिए इसे लागू करने के लिए आपको Foo_Abstract का निर्माता बनाना होगा final
, ओवरराइडिंग को रोकना होगा।
आप इसके बजाय एक अमूर्त गटर की घोषणा कर सकते हैं:
abstract class Foo_Abstract {
abstract public function get_tablename();
}
class Foo extends Foo_Abstract {
protected $tablename = 'tablename';
public function get_tablename() {
return $this->tablename;
}
}
संपत्ति के संदर्भ के आधार पर अगर मैं किसी चाइल्ड ऑब्जेक्ट में एब्सट्रैक्ट ऑब्जेक्ट प्रॉपर्टी की घोषणा को बाध्य करना चाहता हूं, तो मैं static
एब्सट्रैक्ट ऑब्जेक्ट कंस्ट्रक्टर या सेटर / गेट्टर विधियों में संपत्ति के लिए कीवर्ड के साथ एक निरंतर का उपयोग करना पसंद करता हूं । आप वैकल्पिक रूप से उपयोग कर सकते हैंfinal
से विस्तारित कक्षाओं में विधि को ओवरराइड होने से रोकने के लिए हैं।
इसके अलावा बच्चे की वस्तु मूल वस्तु संपत्ति और विधियों को ओवरराइड कर देती है यदि पुनर्परिभाषित किया जाता है। उदाहरण के लिए यदि कोई संपत्ति protected
माता-पिता के रूप में घोषित की जाती है और public
बच्चे के रूप में फिर से परिभाषित की जाती है, तो परिणामी संपत्ति सार्वजनिक होती है। हालांकि अगर संपत्ति को private
अभिभावक में घोषित किया जाता है तो वह बनी रहेगीprivate
बच्चे के लिए उपलब्ध नहीं ।
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;
जैसा कि ऊपर कहा गया है, ऐसी कोई सटीक परिभाषा नहीं है। हालाँकि, मैं इस साधारण वर्कअराउंड का उपयोग करके "अमूर्त" संपत्ति को परिभाषित करने के लिए बाल वर्ग को मजबूर करता हूं:
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
गुणों के लिए समस्या को हल नहीं करता है ।
the only "safe" methods to have in a constructor are private and/or final ones
, क्या मेरा मामला इस तरह का नहीं है? im इसमें निजीकरण का उपयोग कर रहा है
$name
। आप setName()
वास्तव में सेटिंग के बिना फ़ंक्शन को लागू कर सकते हैं $name
।
getName
करने के बजाय इसका उपयोग करना $name
। abstract class Father { abstract protected function getName(); public function foo(){ echo $this->getName();} }
मैंने आज खुद से वही सवाल पूछा है, और मैं अपने दो सेंट जोड़ना चाहूंगा।
जिन abstract
गुणों को हम चाहते हैं उनका कारण यह सुनिश्चित करना है कि उपवर्ग उन्हें परिभाषित करें और जब वे न हों तो अपवादों को फेंक दें। मेरे विशिष्ट मामले में, मुझे कुछ ऐसी चीज की आवश्यकता थी जो static
सहयोगी के साथ काम कर सके ।
आदर्श रूप से मैं कुछ इस तरह से चाहूंगा:
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.
}
मैं इस कार्यान्वयन के साथ समाप्त हुआ
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
{
}
जैसा कि आप देख सकते हैं, A
मैं इसमें परिभाषित नहीं करता $prop
, लेकिन मैं इसे एक static
गटर में उपयोग करता हूं । इसलिए, निम्न कोड काम करता है
B::getProp();
// => 'B prop'
$b = new B();
$b->getProp();
// => 'B prop'
में C
, दूसरे हाथ पर, मैं परिभाषित नहीं करते $prop
, तो मैं अपवाद प्राप्त करें:
C::getProp();
// => Exception!
$c = new C();
$c->getProp();
// => Exception!
मुझे getProp()
अपवाद प्राप्त करने के लिए विधि को कॉल करना चाहिए और मैं इसे क्लास लोडिंग पर प्राप्त नहीं कर सकता, लेकिन यह वांछित व्यवहार के काफी करीब है, कम से कम मेरे मामले में।
मैं कुछ स्मार्ट आदमी (6 महीने में खुद को उर्फ) से बचने के लिए परिभाषित getProp()
करता हूंfinal
class D extends A {
public static function getProp() {
// really smart
}
}
D::getProp();
// => no exception...
जैसा कि आप अपने कोड का परीक्षण करके पता लगा सकते हैं:
घातक त्रुटि: 3 लाइन पर ... में गुणों को सार घोषित नहीं किया जा सकता है
नहीं वहाँ नहीं है। PHP में संपत्तियों को सार घोषित नहीं किया जा सकता है।
हालाँकि, आप एक गेट्टर / सेटर फ़ंक्शन सार को लागू कर सकते हैं, यह वही हो सकता है जिसे आप खोज रहे हैं।
गुण लागू नहीं किए गए हैं (विशेष रूप से सार्वजनिक गुण), वे बस मौजूद हैं (या नहीं):
$foo = new Foo;
$foo->publicProperty = 'Bar';
अमूर्त गुणों की आवश्यकता डिजाइन समस्याओं को इंगित कर सकती है। जबकि कई उत्तर टेम्पलेट विधि पैटर्न को लागू करते हैं और यह काम करता है, यह हमेशा अजीब लगता है।
आइए मूल उदाहरण पर एक नज़र डालें:
abstract class Foo_Abstract {
abstract public $tablename;
}
class Foo extends Foo_Abstract {
//Foo must 'implement' $property
public $tablename = 'users';
}
किसी चीज़ को चिन्हित abstract
करना यह इंगित करना होगा कि यह एक जरूरी चीज है। खैर, एक होना चाहिए मूल्य (इस मामले में) एक आवश्यक निर्भरता है, इसलिए इसे तत्काल के दौरान निर्माणकर्ता को पारित किया जाना चाहिए :
class Table
{
private $name;
public function __construct(string $name)
{
$this->name = $name;
}
public function name(): string
{
return $this->name;
}
}
तब यदि आप वास्तव में एक अधिक ठोस नाम की श्रेणी चाहते हैं, तो आप इस तरह की विरासत प्राप्त कर सकते हैं:
final class UsersTable extends Table
{
public function __construct()
{
parent::__construct('users');
}
}
यह उपयोगी हो सकता है यदि आप डि कंटेनर का उपयोग करते हैं और विभिन्न वस्तुओं के लिए अलग-अलग तालिकाओं को पास करना है।
PHP 7 अमूर्त "गुण" बनाने के लिए काफी आसान बनाता है। ऊपर के रूप में, आप उन्हें अमूर्त फ़ंक्शन बनाकर बनाएंगे, लेकिन PHP 7 के साथ आप उस फ़ंक्शन के लिए रिटर्न प्रकार को परिभाषित कर सकते हैं, जो आधार वर्ग बनाते समय चीजों को बहुत आसान बनाता है जिसे कोई भी विस्तारित कर सकता है।
<?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;
यदि ऑब्जेक्ट के जीवनकाल के दौरान टैबलेन का मान कभी नहीं बदलेगा, तो निम्नलिखित एक सरल लेकिन सुरक्षित कार्यान्वयन होगा।
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';
}
}
यहाँ कुंजी यह है कि स्ट्रिंग मान 'उपयोगकर्ताओं' को निर्दिष्ट किया गया है और चाइल्ड क्लास कार्यान्वयन में सीधे getTablename () में लौटाया गया है। फ़ंक्शन एक "आसानी से" संपत्ति की नकल करता है।
यह पहले से पोस्ट किए गए समाधान के समान है, जिस पर एक अतिरिक्त चर का उपयोग किया जाता है। मुझे मार्को का समाधान भी पसंद है, हालांकि यह थोड़ा अधिक जटिल हो सकता है।