অভিভাবক শ্রেণিতে শিশু শ্রেণির নাম পাওয়া (স্থির প্রসঙ্গ)


93

আমি পুনরায় ব্যবহার এবং সরলতার কথা মাথায় রেখে একটি ORM গ্রন্থাগার তৈরি করছি; আমি বোকা উত্তরাধিকারের সীমাবদ্ধতার দ্বারা আটকে গিয়েছি তা বাদ দিয়ে সবকিছু ঠিকঠাক হয়। নীচের কোডটি বিবেচনা করুন:

class BaseModel {
    /*
     * Return an instance of a Model from the database.
     */
    static public function get (/* varargs */) {
        // 1. Notice we want an instance of User
        $class = get_class(parent); // value: bool(false)
        $class = get_class(self);   // value: bool(false)
        $class = get_class();       // value: string(9) "BaseModel"
        $class =  __CLASS__;        // value: string(9) "BaseModel"

        // 2. Query the database with id
        $row = get_row_from_db_as_array(func_get_args());

        // 3. Return the filled instance
        $obj = new $class();
        $obj->data = $row;
        return $obj;
    }
}

class User extends BaseModel {
    protected $table = 'users';
    protected $fields = array('id', 'name');
    protected $primary_keys = array('id');
}
class Section extends BaseModel {
    // [...]
}

$my_user = User::get(3);
$my_user->name = 'Jean';

$other_user = User::get(24);
$other_user->name = 'Paul';

$my_user->save();
$other_user->save();

$my_section = Section::get('apropos');
$my_section->delete();

স্পষ্টতই, আমি যে আচরণটি প্রত্যাশা করছিলাম এটি এটি নয় (যদিও আসল আচরণটিও বোঝায়) তবে আপনি যদি আমার ছেলেরা অভিভাবক শ্রেণিতে, শিশু শ্রেণির নাম অর্জনের কোনও উপায় সম্পর্কে জানেন তবে তা হয়।

উত্তর:


100

সংক্ষেপে. সপ্তাহের দিন. পিএইচপি 4 এ আপনি একটি ভয়ঙ্কর হ্যাক প্রয়োগ করতে পারেন (পরীক্ষা করুন debug_backtrace()) তবে এই পদ্ধতিটি পিএইচপি 5 তে কাজ করে না। তথ্যসূত্র:

সম্পাদনা করুন : পিএইচপি 5.3 (মন্তব্যে উল্লিখিত) এ লেট স্ট্যাটিক বাইন্ডিংয়ের একটি উদাহরণ। নোট করুন এটির বর্তমান বাস্তবায়নে ( এসআরসি ) সম্ভাব্য সমস্যা রয়েছে ।

class Base {
    public static function whoAmI() {
        return get_called_class();
    }
}

class User extends Base {}

print Base::whoAmI(); // prints "Base"
print User::whoAmI(); // prints "User"

হ্যাঁ, আমি মাত্র পড়লাম debug_backtrace().. একটি সম্ভাব্য সমাধান হ'ল পিএইচপি 5.3 থেকে দেরি স্ট্যাটিক বাইন্ডিং ব্যবহার করা হবে তবে এটি আমার ক্ষেত্রে সম্ভাবনা নয়। ধন্যবাদ.
saalaa

188

আপনি যদি কোনও স্থির প্রসঙ্গের বাইরে এটি করার কোনও উপায় কল্পনা করতে সক্ষম হন তবে আপনাকে পিএইচপি 5.3 এর জন্য অপেক্ষা করার দরকার নেই। পিএইচপি 5.2.9 এ, প্যারেন্ট ক্লাসের একটি অ স্থিত পদ্ধতিতে আপনি এটি করতে পারেন:

get_class($this);

এবং এটি শিশু শ্রেণীর নামটি স্ট্রিং হিসাবে ফিরিয়ে দেবে।

অর্থাত্

class Parent() {
    function __construct() {
        echo 'Parent class: ' . get_class() . "\n" . 'Child class: ' . get_class($this);
    }
}

class Child() {
    function __construct() {
        parent::construct();
    }
}

$x = new Child();

এই আউটপুট হবে:

Parent class: Parent
Child class: Child

মিষ্টি হাহ?


11
আপনি যদি বিমূর্ত ক্লাস ব্যবহার করছেন তবে এটি অবশ্যই জানা উচিত।
লেভি মরিসন

4
আমার মনে হয় $x = new Parent();হওয়া উচিত $x = new Child();
জাস্টিন সি

এই তো প্যানসিট!
বিডালিনা

শিশু শ্রেণি
নির্মাতারা

22

আমি জানি এই প্রশ্নটি আসলেই পুরানো, তবে শ্রেণীর নাম সম্বলিত প্রতিটি শ্রেণীর একটি সম্পত্তি সংজ্ঞার চেয়ে আরও কার্যকর সমাধানের সন্ধানকারীদের জন্য:

আপনি staticএটির জন্য কীওয়ার্ডটি ব্যবহার করতে পারেন ।

যেমন পিএইচপি ডকুমেন্টেশনে এই অবদানকারী নোটটিতে ব্যাখ্যা করা হয়েছে

staticশব্দ সাব বর্গ যা থেকে একটি পদ্ধতি বলা হয় অ্যাক্সেস করতে একটি সুপার শ্রেণীর ভিতরের ব্যবহার করা যাবে।

উদাহরণ:

class Base
{
    public static function init() // Initializes a new instance of the static class
    {
        return new static();
    }

    public static function getClass() // Get static class
    {
        return static::class;
    }

    public function getStaticClass() // Non-static function to get static class
    {
        return static::class;
    }
}

class Child extends Base
{

}

$child = Child::init();         // Initializes a new instance of the Child class

                                // Output:
var_dump($child);               // object(Child)#1 (0) {}
echo $child->getStaticClass();  // Child
echo Child::getClass();         // Child

4
ধন্যবাদ! রিফ্লেকশনক্লাসের সাথে লড়াই static()করে যাচ্ছিল কিন্তু কলিংয়ের পথে যাওয়ার উপায়!
Godbout

18

আমি এটির পুরানো পোস্ট জানি তবে আমি যে সমাধানটি পেয়েছি তা ভাগ করতে চাই।

পিএইচপি 7+ এর সাথে পরীক্ষিত ফাংশন লিঙ্কটি ব্যবহার get_class()করুন

<?php
abstract class bar {
    public function __construct()
    {
        var_dump(get_class($this));
        var_dump(get_class());
    }
}

class foo extends bar {
}

new foo;
?>

উপরের উদাহরণটি আউটপুট দেবে:

string(3) "foo"
string(3) "bar"

6

আপনি get_called_class () ব্যবহার করতে না চাইলে আপনি লেট স্ট্যাটিক বাইন্ডিং (পিএইচপি 5.3+) এর অন্যান্য কৌশল ব্যবহার করতে পারেন। তবে এই ক্ষেত্রে ক্ষতির দিকটি আপনার প্রতিটি মডেলটিতে getClass () পদ্ধতি থাকা দরকার। কোন বড় বিষয় আইএমও নয়।

<?php

class Base 
{
    public static function find($id)
    {
        $table = static::$_table;
        $class = static::getClass();
        // $data = find_row_data_somehow($table, $id);
        $data = array('table' => $table, 'id' => $id);
        return new $class($data);
    }

    public function __construct($data)
    {
        echo get_class($this) . ': ' . print_r($data, true) . PHP_EOL;
    }
}

class User extends Base
{
    protected static $_table = 'users';

    public static function getClass()
    {
        return __CLASS__;
    }
}

class Image extends Base
{
    protected static $_table = 'images';

    public static function getClass()
    {
        return __CLASS__;
    }
}

$user = User::find(1); // User: Array ([table] => users [id] => 1)  
$image = Image::find(5); // Image: Array ([table] => images [id] => 5)

2

এটি সম্ভবত আপনি কারখানার নিদর্শন হিসাবে একটি সিঙ্গলটন প্যাটার্ন ব্যবহার করার চেষ্টা করছেন বলে মনে হচ্ছে। আমি আপনার নকশা সিদ্ধান্ত মূল্যায়নের সুপারিশ করব। যদি একটি সিঙ্গলটন সত্যিই উপযুক্ত হয় তবে আমি কেবল স্থিতিশীল পদ্ধতি ব্যবহার করার পরামর্শ দিচ্ছি যেখানে উত্তরাধিকার পছন্দ হয় না

class BaseModel
{

    public function get () {
        echo get_class($this);

    }

    public static function instance () {
        static $Instance;
        if ($Instance === null) {
            $Instance = new self;

        }
        return $Instance;
    }
}

class User
extends BaseModel
{
    public static function instance () {
        static $Instance;
        if ($Instance === null) {
            $Instance = new self;

        }
        return $Instance;
    }
}

class SpecialUser
extends User
{
    public static function instance () {
        static $Instance;
        if ($Instance === null) {
            $Instance = new self;

        }
        return $Instance;
    }
}


BaseModel::instance()->get();   // value: BaseModel
User::instance()->get();        // value: User
SpecialUser::instance()->get(); // value: SpecialUser

.. না। আমি বোঝার চেষ্টা করছিলাম তা আপনি বুঝতে পারেন নি, তবে এটি কারণ আমি এটি ভালভাবে ব্যাখ্যা করিনি :)। প্রকৃতপক্ষে, আমি কেবল একটি প্রদত্ত মডেলের উদাহরণ ((এটি ব্যবহারকারী, ভূমিকা বা যাই হোক না কেন)) পেতে একটি স্থিতিশীল পদ্ধতি (বেসমোডেলে প্রয়োগ করা) সরবরাহ করার চেষ্টা করছি। আমি প্রশ্নটি আপডেট করব ..
সালাআ

ঠিক আছে, আপডেট হয়েছে। অবশ্যই বেসমোডেল ক্লাসে আরও অনেকগুলি পদ্ধতি রয়েছে, যার মধ্যে কিছু রয়েছে যা অবজেক্টে কী পরিবর্তন হয়েছে তা ট্র্যাক করে রাখুন এবং কেবল যা চ্যাজ করেছে ইত্যাদি আপডেট করুন ... তবে যাইহোক আপনাকে ধন্যবাদ :)।
saalaa

2

হতে পারে এটি আসলে প্রশ্নের উত্তর দিচ্ছে না, তবে আপনি টাইপটি নির্দিষ্ট করে () পেতে একটি প্যারামিটার যুক্ত করতে পারেন। তাহলে আপনি কল করতে পারেন

BaseModel::get('User', 1);

পরিবর্তে ব্যবহারকারীকে ফোন করুন :: get ()। সাবক্লাসে একটি get পদ্ধতি বিদ্যমান কিনা তা পরীক্ষা করতে আপনি বেসমোডেল :: get () এ যুক্তি যুক্ত করতে পারেন এবং তারপরে যদি আপনি সাবক্লাসটিকে ওভাররাইড করার অনুমতি দিতে চান তবে কল করুন।

অন্যথায় আমি স্পষ্টতই ভাবতে পারি যে একমাত্র উপায় হ'ল প্রতিটি সাবক্লাসে স্টাফ যুক্ত করা, যা বোকামি:

class BaseModel {
    public static function get() {
        $args = func_get_args();
        $className = array_shift($args);

        //do stuff
        echo $className;
        print_r($args);
    }
}

class User extends BaseModel {
    public static function get() { 
        $params = func_get_args();
        array_unshift($params, __CLASS__);
        return call_user_func_array( array(get_parent_class(__CLASS__), 'get'), $params); 
    }
}


User::get(1);

সম্ভবত আপনি যদি ব্যবহারকারীকে সাবস্ক্লস করেন তবে এটি সম্ভবত ভেঙে যাবে তবে আমি মনে করি আপনি সেই ক্ষেত্রে এর get_parent_class(__CLASS__)সাথে প্রতিস্থাপন করতে পারবেন'BaseModel'


প্রকৃতপক্ষে হ্যাঁ. এই পিএইচপি সীমাবদ্ধতার আমার নকশাটি পর্যালোচনা করতে বাধ্য করার দুর্দান্ত সুবিধা ছিল। এটি দেখতে আরও অনেক বেশি $ সংযোগ-> পাওয়া ('ব্যবহারকারী', 24) এর মতো দেখাবে; যেহেতু এটি একই সাথে একাধিক সংযোগের অনুমতি দেয় এবং শব্দার্থগতভাবে আরও সঠিক। তবে আপনি একটি পয়েন্ট পেয়েছেন :)।
saalaa

অ্যারে_শিফ্টটি ধীর বলে মনে হচ্ছে কারণ এটি অ্যারের প্রতিটি কী পরিবর্তন করতে হবে ... পরিবর্তে কেবল $ আরগস [0];
Xesau

0

সমস্যাটি কোনও ভাষার সীমাবদ্ধতা নয়, এটি আপনার নকশা। আপনার ক্লাস আছে মনে করবেন না; স্থিতিশীল পদ্ধতিগুলি অবজেক্ট-ওরিয়েন্টেড ডিজাইনের পরিবর্তে একটি পদ্ধতিগত বিশ্বাস করে। আপনি কিছু রূপে বৈশ্বিক রাষ্ট্রও ব্যবহার করছেন। ( get_row_from_db_as_array()ডাটাবেস কোথায় পাওয়া যায় তা কীভাবে জানতে পারে?) এবং অবশেষে ইউনিট পরীক্ষা করা খুব কঠিন বলে মনে হচ্ছে।

এই লাইন বরাবর কিছু চেষ্টা করুন।

$db = new DatabaseConnection('dsn to database...');
$userTable = new UserTable($db);
$user = $userTable->get(24);

0

প্রেস্টনের উত্তরে দুটি ভিন্নতা:

1)

class Base 
{
    public static function find($id)
    {
        $table = static::$_table;
        $class = static::$_class;
        $data = array('table' => $table, 'id' => $id);
        return new $class($data);
    }
}

class User extends Base
{
    public static $_class = 'User';
}

2)

class Base 
{
    public static function _find($class, $id)
    {
        $table = static::$_table;
        $data = array('table' => $table, 'id' => $id);
        return new $class($data);
    }
}

class User extends Base
{
    public static function find($id)
    {
        return self::_find(get_class($this), $id);
    }
}

দ্রষ্টব্য: _ দিয়ে একটি সম্পত্তি নাম শুরু করা একটি সম্মেলন যা মূলত "আমি জানি আমি এই প্রকাশ্যে এনেছি, তবে এটি সত্যই রক্ষা করা উচিত ছিল, তবে আমি তা করতে পারিনি এবং আমার লক্ষ্য অর্জন করতে পারিনি"

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