পিএইচপি বিমূর্ত বৈশিষ্ট্য


126

পিএইচপি-তে বিমূর্ত শ্রেণীর বৈশিষ্ট্য সংজ্ঞায়িত করার কোনও উপায় আছে কি?

abstract class Foo_Abstract {
    abstract public $tablename;
}

class Foo extends Foo_Abstract {
    //Foo must 'implement' $property
    public $tablename = 'users';   
}

উত্তর:


154

সম্পত্তি সংজ্ঞায়িত করার মতো কোনও জিনিস নেই।

আপনি কেবলমাত্র বৈশিষ্ট্যগুলি ঘোষণা করতে পারেন কারণ এগুলি আরম্ভের সময় স্মৃতিতে সংরক্ষিত ডেটার ধারক।

অন্যদিকে কোনও ফাংশনকে (প্রকারের নাম, পরামিতি) সংজ্ঞায়িত না করে (ফাংশন বডি অনুপস্থিত) ঘোষণা করা যায় এবং এভাবে বিমূর্ত করা যেতে পারে।

"বিমূর্ত" কেবলমাত্র ইঙ্গিত করে যে কোনও কিছু ঘোষিত হয়েছিল তবে সংজ্ঞা দেওয়া হয়নি এবং তাই এটি ব্যবহারের আগে আপনাকে এটি সংজ্ঞায়িত করতে হবে বা এটি অকেজো হয়ে যায়।


58
স্ট্যাটিক বৈশিষ্ট্যগুলিতে 'বিমূর্ত' শব্দটি ব্যবহার করা যায়নি - এর কোনও স্পষ্ট কারণ নেই তবে কিছুটা আলাদা অর্থ সহ। উদাহরণস্বরূপ এটি ইঙ্গিত করতে পারে যে একটি সাবক্লাসটি সম্পত্তিটির জন্য একটি মান সরবরাহ করতে হবে।
ফ্রোডবোরলি

2
টাইপস্ক্রিপ্টে বিমূর্ত বৈশিষ্ট্য এবং অ্যাক্সেসর রয়েছে । এটি দুঃখজনক যে পিএইচপি-তে এটি অসম্ভব।
Зеленько

52

না, সংকলক সহ এটি প্রয়োগ করার কোনও উপায় নেই, আপনাকে চলকটির জন্য রান-টাইম চেক (কনস্ট্রাক্টারে বলুন) ব্যবহার করতে হবে $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 এর উত্পন্ন শ্রেণীর জন্য প্রয়োগ করার জন্য আপনাকে finalওভাররাইডিং প্রতিরোধ করে Foo_Abstract এর কনস্ট্রাক্টর তৈরি করতে হবে ।

পরিবর্তে আপনি একটি বিমূর্ত গেটার ঘোষণা করতে পারেন:

abstract class Foo_Abstract {
  abstract public function get_tablename();
}

class Foo extends Foo_Abstract {
  protected $tablename = 'tablename';
  public function get_tablename() {
    return $this->tablename;
  }
}

দুর্দান্ত বৈশিষ্ট্য, আমি পছন্দ করি আপনি কীভাবে বিমূর্ত বৈশিষ্ট্য প্রয়োগ করেন।
ম্যাথিউ ডুমুলিন

4
এটি আপনাকে বিমূর্ত বেস শ্রেণিতে কনস্ট্রাক্টরকে চূড়ান্ত করতে হবে।
hakre

3
কিছু ব্যাখ্যা: আপনি যদি কনস্ট্রাক্টরের অভ্যন্তরে চেকটি করেন এবং এটি বাধ্যতামূলক হওয়া উচিত, আপনার অবশ্যই এটি নিশ্চিত করা দরকার যে এটি প্রতিটি ইনস্ট্যান্টেশনে কার্যকর হয়েছে। সুতরাং আপনার এটি প্রতিরোধ করা দরকার যা মুছে ফেলা হয়, যেমন ক্লাস প্রসারিত করে এবং নির্মাণকারীকে প্রতিস্থাপন করে। চূড়ান্ত শব্দ আপনি এটা করতে সম্ভব হবে।
hakre

1
আমি "বিমূর্ত গেটর" সমাধানটি পছন্দ করি। আপনি যখন ক্লাসের বিমূর্তে কোনও ফাংশন ঘোষণা করেন, আপনাকে অবশ্যই ক্লাসটি নিজেকে বিমূর্ত ঘোষণা করতে হবে। এর অর্থ বর্ধিত এবং পুরোপুরি প্রয়োগ না করা হলে শ্রেণিটি ব্যবহারযোগ্য able এই শ্রেণিটি প্রসারিত করার সময়, আপনাকে অবশ্যই "গিটার" ফাংশনের জন্য একটি প্রয়োগকরণ সরবরাহ করতে হবে। এর অর্থ হ'ল আপনাকে অবশ্যই প্রসারিত শ্রেণীর ভিতরে সম্পর্কিত সম্পত্তি তৈরি করতে হবে, কারণ ফাংশনে অবশ্যই কিছু ফিরতে হবে। এই প্যাটার্নটি অনুসরণ করে আপনি একই ফল পাবেন যেন আপনি কোনও বিমূর্ত সম্পত্তি ঘোষণা করে, এটিও একটি পরিষ্কার এবং পরিষ্কার পদ্ধতির। এটি আসলে এটি হয়ে গেছে।
স্যালাইভান

1
একটি বিমূর্ত গেটর ব্যবহার করে এটি স্থিরমূল্য ফেরত দেওয়ার বিপরীতে যখন কোনও মানটি বোধ করে তখন একটি মান উত্পন্ন করে এটি প্রয়োগ করতে দেয় । একটি বিমূর্ত সম্পত্তি আপনাকে এটি করতে অনুমতি দেবে না, বিশেষত একটি স্থির সম্পত্তি।
টোবিয়া

27

সম্পত্তির প্রসঙ্গের উপর নির্ভর করে যদি আমি কোনও শিশু অবজেক্টে কোনও বিমূর্ত বস্তুর সম্পত্তি ঘোষণার জন্য বাধ্য করতে চাই, তবে আমি 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;

4
এখানে সর্বাধিক মার্জিত সমাধান
জেনি থিউনিসেন

24

উপরে বর্ণিত হিসাবে, এর মতো সঠিক সংজ্ঞা নেই। আমি তবে এই সহজ সরল কৌশলটি শিশু শ্রেণিকে "বিমূর্ত" সম্পত্তি সংজ্ঞায়িত করতে বাধ্য করার জন্য ব্যবহার করি:

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বৈশিষ্ট্যগুলির জন্য সমস্যাটি সমাধান করে না ।
রবার্ট

1
আমি মনে করি না বিমূর্ত পদ্ধতিগুলির জন্য আপনার ব্যক্তিগত থাকতে পারে।
জোড়জি

@ ফেট01 যেমন আমি বুঝতে পেরেছি, মন্তব্যে নিজেই জানিয়েছে যে the only "safe" methods to have in a constructor are private and/or final onesআমার মতো ঘটনা কি ঘটেনি ? আমি এতে বেসরকারী ব্যবহার করছি
উলকাস

4
এটি দেখতে দুর্দান্ত দেখাচ্ছে তবে এটি কোনও শিশু শ্রেণিকে আসলে সেট করতে বাধ্য করে না $name। আপনি setName()কার্যটি এটি সেট না করেই বাস্তবায়ন করতে পারেন $name
ডাব্লু ইইউ

3
আমি মনে করি getNameপরিবর্তে ব্যবহারের $nameচেয়ে আরও ভাল কাজ করা। abstract class Father { abstract protected function getName(); public function foo(){ echo $this->getName();} }
হামিদ

7

আমি আজ নিজেকে একই প্রশ্ন জিজ্ঞাসা করেছি, এবং আমি আমার দুটি সেন্ট যুক্ত করতে চাই।

যে কারণগুলিতে আমরা 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() ব্যতিক্রমটি পেতে আমাকে অবশ্যই পদ্ধতিটি কল করতে হবে এবং আমি এটি ক্লাস লোডিংয়ে পেতে পারি না, তবে এটি আমার ক্ষেত্রে অন্তত পছন্দসই আচরণের খুব কাছাকাছি।

আমি সংজ্ঞায়িত getProp()হিসাবে finalএড়ানোর যে কিছু করার স্মার্ট লোক (6 মাসের মধ্যে নিজেকে ওরফে) করতে প্রলুব্ধ করা হয়

class D extends A {
    public static function getProp() {
        // really smart
    }
}

D::getProp();
// => no exception...

এটি খুব বুদ্ধিমান হ্যাক। আশা করি ভবিষ্যতে এটি করার দরকার নেই।
সিএমসিডিগ্রাগনকাই

6

যেমন আপনি কেবল আপনার কোডটি পরীক্ষা করে জানতে পেরেছেন:

মারাত্মক ত্রুটি: বৈশিষ্ট্যগুলি 3 লাইনে ... বিমূর্ত ঘোষণা করা যায় না

কোন নেই. সম্পত্তি পিএইচপি-তে বিমূর্ত ঘোষণা করা যায় না।

তবে আপনি একটি গিটার / সেটার ফাংশন বিমূর্ত প্রয়োগ করতে পারেন, এটি আপনি যা খুঁজছেন তা হতে পারে।

সম্পত্তিগুলি কার্যকর করা হয় না (বিশেষত জনসাধারণের সম্পত্তি), এগুলি সবেমাত্র বিদ্যমান (বা না):

$foo = new Foo;
$foo->publicProperty = 'Bar';

6

বিমূর্ত বৈশিষ্ট্যের প্রয়োজন ডিজাইনের সমস্যাগুলি নির্দেশ করতে পারে। যদিও অনেক উত্তর বিভিন্ন ধরণের টেম্পলেট পদ্ধতি প্যাটার্ন প্রয়োগ করে এবং এটি কার্যকর হয়, এটি সর্বদা অদ্ভুত লাগে।

আসল উদাহরণটি একবার দেখুন:

abstract class Foo_Abstract {
    abstract public $tablename;
}

class Foo extends Foo_Abstract {
    //Foo must 'implement' $property
    public $tablename = 'users';   
}

কিছু চিহ্নিত করার abstractজন্য এটি অবশ্যই থাকা জিনিসকে নির্দেশ করা indicate ঠিক আছে, একটি অবশ্যই মান থাকতে হবে ( এক্ষেত্রে ) একটি প্রয়োজনীয় নির্ভরতা, তাই এটি ইনস্ট্যান্টেশনের সময় কনস্ট্রাক্টরের কাছে দেওয়া উচিত :

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');
    }
}

আপনি ডিআই কনটেইনার ব্যবহার করেন এবং বিভিন্ন বস্তুর জন্য বিভিন্ন টেবিল পাস করতে পারেন তবে এটি কার্যকর হতে পারে।


3

পিএইচপি 7 বিমূর্ত "বৈশিষ্ট্য" তৈরি করার জন্য এটি কিছুটা সহজ করে তোলে। ঠিক উপরের মতো, আপনি বিমূর্ত ফাংশন তৈরি করে এগুলি তৈরি করবেন, তবে পিএইচপি 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;

1

যদি বস্তুর জীবদ্দশায় টেবিলের নামটি কখনই পরিবর্তন না হয় তবে নিম্নলিখিতটি একটি সহজ তবে নিরাপদ বাস্তবায়ন হবে।

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 () এ সরাসরি ফিরে আসে। ফাংশন একটি "পঠনযোগ্য" সম্পত্তি নকল করে।

এটি পূর্বে পোস্ট করা সমাধানের সাথে মোটামুটি মিল যার উপর অতিরিক্ত ভেরিয়েবল ব্যবহার করা হয়। আমি মার্কোর সমাধানটিও পছন্দ করি যদিও এটি কিছুটা জটিল হতে পারে।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.