পিএইচপি __get এবং __ সেট যাদু পদ্ধতি


86

যদি না আমি পুরোপুরি ভুল নই, __getএবং __setপদ্ধতি ওভারলোডিং অনুমতি অনুমিত হয় → getএবং set

উদাহরণস্বরূপ, নিম্নলিখিত বিবৃতিগুলি __getপদ্ধতিটি গ্রহণ করা উচিত :

echo $foo->bar;
$var = $foo->bar;

এবং নিম্নলিখিতটি __setপদ্ধতিটি ব্যবহার করা উচিত :

$foo->bar = 'test';

এটি আমার কোডে কাজ করে না, এবং এই সাধারণ উদাহরণ দিয়ে পুনরুত্পাদনযোগ্য:

class foo {

    public $bar;
    public function __get($name) {

        echo "Get:$name";
        return $this->$name;
    }

    public function __set($name, $value) {

        echo "Set:$name to $value";
        $this->$name = $value;
    }
}


$foo = new foo();

echo $foo->bar;
$foo->bar = 'test';

echo "[$foo->bar]";

এটি কেবল এর ফলাফল:

[test]

die()সেখানে কিছু কল করা দেখায় যে এটি একেবারেই হিট করছে না।

আপাতত, আমি কেবল এটি স্ক্রু বলেছি, এবং নিজেই ব্যবহার করছি __get এখনই এটির প্রয়োজন যেখানে , তবে এটি খুব গতিশীল নয় এবং জ্ঞানের প্রয়োজন যে 'ওভারলোডেড' কোডটি আসলে বিশেষভাবে বলা না হলে বলা হয় না। আমি এটি জানতে চাই যে এটি হয় যেভাবে বুঝেছিল যে এটি করা উচিত বা এটি কেন কাজ করছে না সেভাবে কাজ করে না।

এই চলছে php 5.3.3

উত্তর:


166

__get, __set, __callএবং __callStaticপ্রার্থনা যখন পদ্ধতি বা সম্পত্তি অ্যাক্সেসযোগ্য নয়। আপনার $barসর্বজনীন এবং এর জন্য অ্যাক্সেসযোগ্য নয়।

ম্যানুয়ালটিতে সম্পত্তি ওভারলোডিংয়ের বিভাগটি দেখুন :

  • __set() দুর্গম বৈশিষ্ট্যগুলিতে ডেটা লেখার সময় চালানো হয়।
  • __get() অ্যাক্সেসযোগ্য সম্পত্তি থেকে ডেটা পড়ার জন্য ব্যবহার করা হয়।

ম্যাজিক পদ্ধতিগুলি গেটর এবং সেটটারগুলির বিকল্প নয়। তারা কেবল আপনাকে পদ্ধতি কল বা সম্পত্তি অ্যাক্সেস পরিচালনা করতে দেয় যা অন্যথায় একটি ত্রুটির কারণ হতে পারে। যেমন ত্রুটি পরিচালনার সাথে সম্পর্কিত আরও রয়েছে। এছাড়াও মনে রাখবেন যে তারা যথাযথ গেটর এবং সেটার বা সরাসরি পদ্ধতি কলগুলি ব্যবহার করার চেয়ে যথেষ্ট ধীর।


6
এর বিশদটি জানাতে, কেবলমাত্র "পাবলিক $ বার" সরিয়ে ফেলুন যাতে সম্পত্তিটির আর অস্তিত্ব থাকে না এবং এটি কবজির মতো কাজ করবে।
স্টিফেন মুলার

ধন্যবাদ পুঙ্খানুপুঙ্খভাবে পুস্তকটি না পড়ার পরিবর্তে এবং এর জন্য কয়েকজন ব্লগের উদাহরণ দেখার জন্য আমি এটি পেয়েছি;) এখনও পিএইচপি-তে সত্য অপারেটর ওভারলোডিংয়ের জন্য অপেক্ষা করছি।
এয়ারবায়ার

@ বিয়ারে সারা গলেমনর একটি পুরানো পিইসিএল প্যাকেজ রয়েছে যা আপনাকে অপারেটরদের ওভারলোড করার অনুমতি দেয় । যদিও এটি পিএইচপি কোডের সাথে সামঞ্জস্যপূর্ণ তা জানেন না।
গর্ডন

4
@ পুয়া এটি কারণ node$ ফু এর সম্পত্তি নয় বরং এর সম্পত্তি doesNotExist। সুতরাং, 'doNotExist' না হওয়া অবধি কোনও উপাদান (যা __set প্রয়োগ করে বা নোড নামে একটি সরকারী সম্পত্তি রয়েছে) এটি কাজ করবে না।
Tivie

4
@ অ্যালেন হ্যাঁ, এটি করে।
গর্ডন

34

আমি মাধ্যমে সব মান জমা করার জন্য একটি অ্যারের ব্যবহার করতে বলতে চাই __set()

class foo {

    protected $values = array();

    public function __get( $key )
    {
        return $this->values[ $key ];
    }

    public function __set( $key, $value )
    {
        $this->values[ $key ] = $value;
    }

}

এইভাবে আপনি নিশ্চিত $valuesহন যে সংঘর্ষ এড়াতে আপনি অন্যভাবে ভেরিয়েবলগুলি অ্যাক্সেস করতে পারবেন না (নোটটি সুরক্ষিত রয়েছে)


19

থেকে পিএইচপি ম্যানুয়াল :

  • অ্যাক্সেসযোগ্য বৈশিষ্ট্যগুলিতে ডেটা লেখার সময় __set () চালিত হয়।
  • __get () অ্যাক্সেসযোগ্য সম্পত্তি থেকে ডেটা পড়ার জন্য ব্যবহৃত হয়।

এটি কেবল অ্যাক্সেস অযোগ্য সম্পত্তি পড়ার / লেখার জন্য বলা হয় । আপনার সম্পত্তি তবে সর্বজনীন, যার অর্থ এটি অ্যাক্সেসযোগ্য। সুরক্ষিতটিতে অ্যাক্সেস মডিফায়ার পরিবর্তন করা সমস্যার সমাধান করে।


7

বেরির উত্তরের প্রসারকে প্রসারিত করার জন্য, সুরক্ষিতভাবে অ্যাক্সেসের স্তর নির্ধারণের ফলে __get এবং __set স্পষ্টভাবে ঘোষিত বৈশিষ্ট্য (যখন শ্রেণীর বাইরে প্রবেশ করা যায়, কমপক্ষে) এবং গতি যথেষ্ট ধীর হয়ে যায়, আমি অন্য প্রশ্নের একটি মন্তব্য উদ্ধৃত করব allows এই বিষয়ে এবং এটি যেভাবেই হোক ব্যবহার করার জন্য একটি কেস তৈরি করুন:

আমি সম্মত হই যে __get একটি কাস্টম গিফট ফাংশন (একই জিনিসগুলি করা) এর চেয়ে ধীর গতির, এটি __get () এর জন্য 0.0124455 সময় এবং এই 0.0024445 10000 লুপের পরে কাস্টম গেট () জন্য। - মেলসি 23 নভেম্বর '12 এ 22:32 সেরা অনুশীলন: পিএইচপি যাদু পদ্ধতি __ সেট এবং __get

মেলসির পরীক্ষাগুলি অনুসারে, যথেষ্ট ধীর প্রায় 5 গুণ ধীর er এটি অবশ্যই যথেষ্ট ধীর, তবে এটিও নোট করুন যে পরীক্ষাগুলি দেখায় যে আপনি এখনও 10 সেকেন্ডে এই পদ্ধতিতে কোনও সম্পত্তি অ্যাক্সেস করতে পারবেন, লুপ পুনরাবৃত্তির জন্য সময় গণনা করতে পারার জন্য প্রায় এক সেকেন্ডের প্রায় 1/100। এটি প্রকৃত গেট এবং সেট পদ্ধতির সংজ্ঞায়নের তুলনায় যথেষ্ট ধীর এবং এটি একটি সংক্ষিপ্ত বিবরণ, তবে জিনিসগুলির দুর্দান্ত পরিকল্পনায় এমনকি 5 গুণ ধীরে ধীরে ধীরে ধীরে কখনও ধীর হয় না।

অপারেশনটির কম্পিউটিং সময়টি এখনও তুচ্ছ এবং বাস্তব বিশ্বের অ্যাপ্লিকেশনগুলির 99% হিসাবে বিবেচনা করার মতো নয়। কেবলমাত্র যখন এটিকে এড়ানো উচিত তখনই আপনি যখন কোনও একক অনুরোধে 10,000 টিরও বেশি বার বৈশিষ্ট্যগুলি অ্যাক্সেস করতে যাচ্ছেন। উচ্চ ট্র্যাফিক সাইটগুলি তাদের অ্যাপ্লিকেশনগুলি চালিয়ে যেতে আরও কয়েকটি সার্ভার নিক্ষেপ করতে না পারলে সত্যিই কিছু ভুল করছে। উচ্চ ট্র্যাফিক সাইটের ফুটারে একটি একক লাইন পাঠ্য বিজ্ঞাপন যেখানে অ্যাক্সেস রেট একটি সমস্যা হয়ে দাঁড়ায় সম্ভবত সেই পাঠ্যের লাইনটি সহ 1000 সার্ভারের খামারের জন্য অর্থ প্রদান করতে পারে। শেষ ব্যবহারকারী কখনই পৃষ্ঠাটি লোড হতে এত বেশি সময় নিচ্ছে তা ভেবে তাদের আঙ্গুলগুলি কখনই ট্যাপ করবেন না কারণ আপনার অ্যাপ্লিকেশনটির সম্পত্তি অ্যাক্সেস এক সেকেন্ডের মিলিয়ন ভাগ সময় নেয়।

আমি বলছি। নেট মধ্যে একটি পটভূমি থেকে আসা বিকাশকারী হিসাবে এই কথা বলা, তবে গ্রাহকের কাছে অদৃশ্য প্রাপ্তি এবং সেট পদ্ধতিগুলি NET এর আবিষ্কার নয়। এগুলি কেবল এগুলি ছাড়া সম্পত্তি নয়, এবং এই যাদু পদ্ধতিগুলি তাদের বৈশিষ্ট্যগুলির বৈশিষ্ট্যগুলিকে একেবারেই "বৈশিষ্ট্য" বলার জন্য পিএইচপি এর বিকাশকারীদের সংরক্ষণের অনুগ্রহ। এছাড়াও, পিএইচপি-র জন্য ভিজ্যুয়াল স্টুডিও এক্সটেনশন সুরক্ষিত বৈশিষ্ট্যগুলির সাথে ইন্টেলিজেন্সকে সমর্থন করে, সেই কৌশলটি মাথায় রেখে think আমি এইভাবে ম্যাজিক __get এবং __set পদ্ধতিগুলি ব্যবহার করে পর্যাপ্ত বিকাশকারীদের সাথে ভাবতে পারি, পিএইচপি বিকাশকারীরা বিকাশকারী সম্প্রদায়কে পূরণ করতে মৃত্যুদন্ড কার্যকর করার সময়টি নির্ধারণ করতে পারে।

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

/** Base class with magic property __get() and __set() support for defined properties. */
class Component {
    /** Gets the properties of the class stored after removing the original
     * definitions to trigger magic __get() and __set() methods when accessed. */
    protected $properties = array();

    /** Provides property get support. Add a case for the property name to
     * expand (no break;) or replace (break;) the default get method. When
     * overriding, call parent::__get($name) first and return if not null,
     * then be sure to check that the property is in the overriding class
     * before doing anything, and to implement the default get routine. */
    public function __get($name) {
        $caller = array_shift(debug_backtrace());
        $max_access = ReflectionProperty::IS_PUBLIC;
        if (is_subclass_of($caller['class'], get_class($this)))
            $max_access = ReflectionProperty::IS_PROTECTED;
        if ($caller['class'] == get_class($this))
            $max_access = ReflectionProperty::IS_PRIVATE;
        if (!empty($this->properties[$name])
            && $this->properties[$name]->class == get_class()
            && $this->properties[$name]->access <= $max_access)
            switch ($name) {
                default:
                    return $this->properties[$name]->value;
            }
    }

    /** Provides property set support. Add a case for the property name to
     * expand (no break;) or replace (break;) the default set method. When
     * overriding, call parent::__set($name, $value) first, then be sure to
     * check that the property is in the overriding class before doing anything,
     * and to implement the default set routine. */
    public function __set($name, $value) {
        $caller = array_shift(debug_backtrace());
        $max_access = ReflectionProperty::IS_PUBLIC;
        if (is_subclass_of($caller['class'], get_class($this)))
            $max_access = ReflectionProperty::IS_PROTECTED;
        if ($caller['class'] == get_class($this))
            $max_access = ReflectionProperty::IS_PRIVATE;
        if (!empty($this->properties[$name])
            && $this->properties[$name]->class == get_class()
            && $this->properties[$name]->access <= $max_access)
            switch ($name) {
                default:
                    $this->properties[$name]->value = $value;
            }
    }

    /** Constructor for the Component. Call first when overriding. */
    function __construct() {
        // Removing and moving properties to $properties property for magic
        // __get() and __set() support.
        $reflected_class = new ReflectionClass($this);
        $properties = array();
        foreach ($reflected_class->getProperties() as $property) {
            if ($property->isStatic()) { continue; }
            $properties[$property->name] = (object)array(
                'name' => $property->name, 'value' => $property->value
                , 'access' => $property->getModifier(), 'class' => get_class($this));
            unset($this->{$property->name}); }
        $this->properties = $properties;
    }
}

কোডটিতে কোনও বাগ থাকলে আমার ক্ষমা চাই।


আমি 'অ্যাক্সেস' => $ সম্পত্তি-> getModifier ()
macki

5

এটি কারণ $ বার একটি সর্বজনীন সম্পত্তি।

$foo->bar = 'test';

উপরেরটি চালানোর সময় যাদু পদ্ধতিটি কল করার দরকার নেই।

public $bar;আপনার ক্লাস থেকে মুছে ফেলা এটিকে সংশোধন করা উচিত।


1

নীচের উদাহরণ হিসাবে সেরা ব্যবহারের যাদু সেট / পূর্বনির্ধারিত কাস্টম সেট সহ পদ্ধতিগুলি পান / পদ্ধতি পান। এইভাবে আপনি দুটি পৃথিবীর সেরা একত্রিত করতে পারেন। গতির ক্ষেত্রে আমি সম্মতি দিচ্ছি যে এগুলি কিছুটা ধীর গতিতে তবে আপনি কী পার্থক্যটি অনুভব করতে পারেন। নীচের উদাহরণগুলি পূর্বনির্ধারিত সেটটারগুলির বিরুদ্ধে ডেটা অ্যারেটিকে বৈধতা দেয়।

"ম্যাজিক পদ্ধতিগুলি গ্রাহক এবং সেটারের বিকল্প নয় They তারা কেবল আপনাকে পদ্ধতি কল বা সম্পত্তি অ্যাক্সেস পরিচালনা করতে দেয় যা অন্যথায় একটি ত্রুটির কারণ হতে পারে" "

এজন্য আমাদের দু'জনকেই ব্যবহার করা উচিত।

ক্লাস আইটেম উদাহরণ

    /*
    * Item class
    */
class Item{
    private $data = array();

    function __construct($options=""){ //set default to none
        $this->setNewDataClass($options); //calling function
    }

    private function setNewDataClass($options){
        foreach ($options as $key => $value) {
            $method = 'set'.ucfirst($key); //capitalize first letter of the key to preserve camel case convention naming
            if(is_callable(array($this, $method))){  //use seters setMethod() to set value for this data[key];      
                $this->$method($value); //execute the setters function
            }else{
                $this->data[$key] = $value; //create new set data[key] = value without seeters;
            }   
        }
    }

    private function setNameOfTheItem($value){ // no filter
        $this->data['name'] = strtoupper($value); //assign the value
        return $this->data['name']; // return the value - optional
    }

    private function setWeight($value){ //use some kind of filter
        if($value >= "100"){ 
            $value = "this item is too heavy - sorry - exceeded weight of maximum 99 kg [setters filter]";
        }
        $this->data['weight'] = strtoupper($value); //asign the value
        return $this->data['weight']; // return the value - optional
    }

    function __set($key, $value){
        $method = 'set'.ucfirst($key); //capitalize first letter of the key to preserv camell case convention naming
        if(is_callable(array($this, $method))){  //use seters setMethod() to set value for this data[key];      
            $this->$method($value); //execute the seeter function
        }else{
            $this->data[$key] = $value; //create new set data[key] = value without seeters;
        }
    }

    function __get($key){
        return $this->data[$key];
    }

    function dump(){
        var_dump($this);
    }
}

INDEX.PHP

$data = array(
    'nameOfTheItem' => 'tv',
    'weight' => '1000',
    'size' => '10x20x30'
);

$item = new Item($data);
$item->dump();

$item->somethingThatDoNotExists = 0; // this key (key, value) will trigger magic function __set() without any control or check of the input,
$item->weight = 99; // this key will trigger predefined setter function of a class - setWeight($value) - value is valid,
$item->dump();

$item->weight = 111; // this key will trigger predefined setter function of a class - setWeight($value) - value invalid - will generate warning.
$item->dump(); // display object info

আউটপুট

object(Item)[1]
  private 'data' => 
    array (size=3)
      'name' => string 'TV' (length=2)
      'weight' => string 'THIS ITEM IS TOO HEAVY - SORRY - EXIDED WEIGHT OF MAXIMUM 99 KG [SETTERS FILTER]' (length=80)
      'size' => string '10x20x30' (length=8)
object(Item)[1]
  private 'data' => 
    array (size=4)
      'name' => string 'TV' (length=2)
      'weight' => string '99' (length=2)
      'size' => string '10x20x30' (length=8)
      'somethingThatDoNotExists' => int 0
object(Item)[1]
  private 'data' => 
    array (size=4)
      'name' => string 'TV' (length=2)
      'weight' => string 'THIS ITEM IS TOO HEAVY - SORRY - EXIDED WEIGHT OF MAXIMUM 99 KG [SETTERS FILTER]' (length=80)
      'size' => string '10x20x30' (length=8)
      'somethingThatDoNotExists' => int 0


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