পিএইচপি-তে বিমূর্ত শ্রেণীর বৈশিষ্ট্য সংজ্ঞায়িত করার কোনও উপায় আছে কি?
abstract class Foo_Abstract {
abstract public $tablename;
}
class Foo extends Foo_Abstract {
//Foo must 'implement' $property
public $tablename = 'users';
}
পিএইচপি-তে বিমূর্ত শ্রেণীর বৈশিষ্ট্য সংজ্ঞায়িত করার কোনও উপায় আছে কি?
abstract class Foo_Abstract {
abstract public $tablename;
}
class Foo extends Foo_Abstract {
//Foo must 'implement' $property
public $tablename = 'users';
}
উত্তর:
সম্পত্তি সংজ্ঞায়িত করার মতো কোনও জিনিস নেই।
আপনি কেবলমাত্র বৈশিষ্ট্যগুলি ঘোষণা করতে পারেন কারণ এগুলি আরম্ভের সময় স্মৃতিতে সংরক্ষিত ডেটার ধারক।
অন্যদিকে কোনও ফাংশনকে (প্রকারের নাম, পরামিতি) সংজ্ঞায়িত না করে (ফাংশন বডি অনুপস্থিত) ঘোষণা করা যায় এবং এভাবে বিমূর্ত করা যেতে পারে।
"বিমূর্ত" কেবলমাত্র ইঙ্গিত করে যে কোনও কিছু ঘোষিত হয়েছিল তবে সংজ্ঞা দেওয়া হয়নি এবং তাই এটি ব্যবহারের আগে আপনাকে এটি সংজ্ঞায়িত করতে হবে বা এটি অকেজো হয়ে যায়।
না, সংকলক সহ এটি প্রয়োগ করার কোনও উপায় নেই, আপনাকে চলকটির জন্য রান-টাইম চেক (কনস্ট্রাক্টারে বলুন) ব্যবহার করতে হবে $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;
}
}
সম্পত্তির প্রসঙ্গের উপর নির্ভর করে যদি আমি কোনও শিশু অবজেক্টে কোনও বিমূর্ত বস্তুর সম্পত্তি ঘোষণার জন্য বাধ্য করতে চাই, তবে আমি 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
আমার মতো ঘটনা কি ঘটেনি ? আমি এতে বেসরকারী ব্যবহার করছি
$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()
ব্যতিক্রমটি পেতে আমাকে অবশ্যই পদ্ধতিটি কল করতে হবে এবং আমি এটি ক্লাস লোডিংয়ে পেতে পারি না, তবে এটি আমার ক্ষেত্রে অন্তত পছন্দসই আচরণের খুব কাছাকাছি।
আমি সংজ্ঞায়িত getProp()
হিসাবে final
এড়ানোর যে কিছু করার স্মার্ট লোক (6 মাসের মধ্যে নিজেকে ওরফে) করতে প্রলুব্ধ করা হয়
class D extends A {
public static function getProp() {
// really smart
}
}
D::getProp();
// => no exception...
যেমন আপনি কেবল আপনার কোডটি পরীক্ষা করে জানতে পেরেছেন:
মারাত্মক ত্রুটি: বৈশিষ্ট্যগুলি 3 লাইনে ... বিমূর্ত ঘোষণা করা যায় না
কোন নেই. সম্পত্তি পিএইচপি-তে বিমূর্ত ঘোষণা করা যায় না।
তবে আপনি একটি গিটার / সেটার ফাংশন বিমূর্ত প্রয়োগ করতে পারেন, এটি আপনি যা খুঁজছেন তা হতে পারে।
সম্পত্তিগুলি কার্যকর করা হয় না (বিশেষত জনসাধারণের সম্পত্তি), এগুলি সবেমাত্র বিদ্যমান (বা না):
$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
জন্য এটি অবশ্যই থাকা জিনিসকে নির্দেশ করা 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');
}
}
আপনি ডিআই কনটেইনার ব্যবহার করেন এবং বিভিন্ন বস্তুর জন্য বিভিন্ন টেবিল পাস করতে পারেন তবে এটি কার্যকর হতে পারে।
পিএইচপি 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;
যদি বস্তুর জীবদ্দশায় টেবিলের নামটি কখনই পরিবর্তন না হয় তবে নিম্নলিখিতটি একটি সহজ তবে নিরাপদ বাস্তবায়ন হবে।
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 () এ সরাসরি ফিরে আসে। ফাংশন একটি "পঠনযোগ্য" সম্পত্তি নকল করে।
এটি পূর্বে পোস্ট করা সমাধানের সাথে মোটামুটি মিল যার উপর অতিরিক্ত ভেরিয়েবল ব্যবহার করা হয়। আমি মার্কোর সমাধানটিও পছন্দ করি যদিও এটি কিছুটা জটিল হতে পারে।