পিএইচপি অ্যাপ্লিকেশনটির জন্য প্লাগইনগুলিকে অনুমতি দেওয়ার সর্বোত্তম উপায়


276

আমি পিএইচপি-তে একটি নতুন ওয়েব অ্যাপ্লিকেশন শুরু করছি এবং এবার প্রায় আমি এমন কিছু তৈরি করতে চাই যা লোকেরা একটি প্লাগইন ইন্টারফেস ব্যবহার করে প্রসারিত করতে পারে।

কীভাবে কেউ তাদের কোডগুলিতে 'হুকস' লেখার বিষয়ে যায় যাতে প্লাগইনগুলি নির্দিষ্ট ইভেন্টগুলির সাথে সংযুক্ত করতে পারে?

উত্তর:


162

আপনি একটি পর্যবেক্ষক প্যাটার্ন ব্যবহার করতে পারেন। এটি সম্পাদন করার একটি সহজ কার্যকরী উপায়:

<?php

/** Plugin system **/

$listeners = array();

/* Create an entry point for plugins */
function hook() {
    global $listeners;

    $num_args = func_num_args();
    $args = func_get_args();

    if($num_args < 2)
        trigger_error("Insufficient arguments", E_USER_ERROR);

    // Hook name should always be first argument
    $hook_name = array_shift($args);

    if(!isset($listeners[$hook_name]))
        return; // No plugins have registered this hook

    foreach($listeners[$hook_name] as $func) {
        $args = $func($args); 
    }
    return $args;
}

/* Attach a function to a hook */
function add_listener($hook, $function_name) {
    global $listeners;
    $listeners[$hook][] = $function_name;
}

/////////////////////////

/** Sample Plugin **/
add_listener('a_b', 'my_plugin_func1');
add_listener('str', 'my_plugin_func2');

function my_plugin_func1($args) {
    return array(4, 5);
}

function my_plugin_func2($args) {
    return str_replace('sample', 'CRAZY', $args[0]);
}

/////////////////////////

/** Sample Application **/

$a = 1;
$b = 2;

list($a, $b) = hook('a_b', $a, $b);

$str  = "This is my sample application\n";
$str .= "$a + $b = ".($a+$b)."\n";
$str .= "$a * $b = ".($a*$b)."\n";

$str = hook('str', $str);
echo $str;
?>

আউটপুট:

This is my CRAZY application
4 + 5 = 9
4 * 5 = 20

মন্তব্য:

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

এটি পিএইচপি-তে একটি প্লাগইন সিস্টেম সম্পাদনের কেবল একটি পদ্ধতি। আরও ভাল বিকল্প আছে, আমি আপনাকে আরও তথ্যের জন্য ওয়ার্ডপ্রেস ডকুমেন্টেশন পরীক্ষা করে নেওয়ার পরামর্শ দিই।


3
নোট করুন যে পিএইচপি> = 5.0 এর জন্য আপনি এসপিএলে সংজ্ঞায়িত পর্যবেক্ষক / সাবজেক্ট ইন্টারফেস ব্যবহার করে এটি প্রয়োগ করতে পারেন: php.net/manual/en/class.splobserver.php
জন কার্টার

20
পেডেন্টিক নোট: এটি পর্যবেক্ষক প্যাটার্নের উদাহরণ নয়। এটি একটি উদাহরণ Mediator Pattern। সত্য পর্যবেক্ষকরা নিখুঁতভাবে বিজ্ঞপ্তি হয়, কোনও বার্তা প্রেরণ বা শর্তাধীন বিজ্ঞপ্তি নেই (বিজ্ঞপ্তিগুলি নিয়ন্ত্রণের জন্য কোনও কেন্দ্রীয় পরিচালকও নেই)। এটি উত্তরটি ভুল করে না , তবে লোকেদের ভুল নামে
ডাকানো

মনে রাখবেন যে একাধিক হুক / শ্রোতাদের ব্যবহার করার সময়, আপনার কেবল দুটি স্ট্রিং বা অ্যারেগুলিই ফিরে আসা উচিত। আমি হাউন্ড সিএমএস - getbutterfly.com/hound এর জন্য অনুরূপ কিছু বাস্তবায়ন করেছি
সিপরিয়ান

59

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

<?php

////////////////////
// PART 1
////////////////////

class Plugin {

    private $_RefObject;
    private $_Class = '';

    public function __construct(&$RefObject) {
        $this->_Class = get_class(&$RefObject);
        $this->_RefObject = $RefObject;
    }

    public function __set($sProperty,$mixed) {
        $sPlugin = $this->_Class . '_' . $sProperty . '_setEvent';
        if (is_callable($sPlugin)) {
            $mixed = call_user_func_array($sPlugin, $mixed);
        }   
        $this->_RefObject->$sProperty = $mixed;
    }

    public function __get($sProperty) {
        $asItems = (array) $this->_RefObject;
        $mixed = $asItems[$sProperty];
        $sPlugin = $this->_Class . '_' . $sProperty . '_getEvent';
        if (is_callable($sPlugin)) {
            $mixed = call_user_func_array($sPlugin, $mixed);
        }   
        return $mixed;
    }

    public function __call($sMethod,$mixed) {
        $sPlugin = $this->_Class . '_' .  $sMethod . '_beforeEvent';
        if (is_callable($sPlugin)) {
            $mixed = call_user_func_array($sPlugin, $mixed);
        }
        if ($mixed != 'BLOCK_EVENT') {
            call_user_func_array(array(&$this->_RefObject, $sMethod), $mixed);
            $sPlugin = $this->_Class . '_' . $sMethod . '_afterEvent';
            if (is_callable($sPlugin)) {
                call_user_func_array($sPlugin, $mixed);
            }       
        } 
    }

} //end class Plugin

class Pluggable extends Plugin {
} //end class Pluggable

////////////////////
// PART 2
////////////////////

class Dog {

    public $Name = '';

    public function bark(&$sHow) {
        echo "$sHow<br />\n";
    }

    public function sayName() {
        echo "<br />\nMy Name is: " . $this->Name . "<br />\n";
    }


} //end class Dog

$Dog = new Dog();

////////////////////
// PART 3
////////////////////

$PDog = new Pluggable($Dog);

function Dog_bark_beforeEvent(&$mixed) {
    $mixed = 'Woof'; // Override saying 'meow' with 'Woof'
    //$mixed = 'BLOCK_EVENT'; // if you want to block the event
    return $mixed;
}

function Dog_bark_afterEvent(&$mixed) {
    echo $mixed; // show the override
}

function Dog_Name_setEvent(&$mixed) {
    $mixed = 'Coco'; // override 'Fido' with 'Coco'
    return $mixed;
}

function Dog_Name_getEvent(&$mixed) {
    $mixed = 'Different'; // override 'Coco' with 'Different'
    return $mixed;
}

////////////////////
// PART 4
////////////////////

$PDog->Name = 'Fido';
$PDog->Bark('meow');
$PDog->SayName();
echo 'My New Name is: ' . $PDog->Name;

পর্ব 1 এ, আপনি এ এর ​​সাথে অন্তর্ভুক্ত থাকতে পারেন require_once() এটিই আপনার পিএইচপি স্ক্রিপ্টের শীর্ষে কল । প্লাগযোগ্য কিছু করার জন্য এটি ক্লাসগুলি লোড করে।

পার্ট 2 এ, যেখানে আমরা একটি ক্লাস লোড করি। দ্রষ্টব্য আমাকে ক্লাসের জন্য বিশেষ কিছু করতে হবে না, যা পর্যবেক্ষক নিদর্শনের তুলনায় উল্লেখযোগ্যভাবে আলাদা।

পার্ট 3 এ, যেখানে আমরা আমাদের ক্লাসটিকে "প্লাগেবল" হিসাবে রূপান্তরিত করি (যা প্লাগইন সমর্থন করে যা আমাদের শ্রেণি পদ্ধতি এবং বৈশিষ্ট্যগুলিকে ওভাররাইড করতে দেয়)। সুতরাং, উদাহরণস্বরূপ, আপনার কাছে একটি ওয়েব অ্যাপ্লিকেশন থাকলে আপনার একটি প্লাগইন রেজিস্ট্রি থাকতে পারে এবং আপনি এখানে প্লাগইনগুলি সক্রিয় করতে পারেন। Dog_bark_beforeEvent()ফাংশনটিও লক্ষ্য করুন । যদি আমি $mixed = 'BLOCK_EVENT'ফেরতের বিবৃতি দেওয়ার আগে সেট করে রাখি তবে এটি কুকুরটিকে ছাঁটাই থেকে আটকাবে এবং কুকুর_বার্ক_পরেও আটকে দেবে কারণ কোনও ইভেন্ট হবে না।

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

তাহলে এটা কিভাবে কাজ করে? ঠিক আছে, আসুন বাতিল করা যাক eval()(যা প্রত্যেকে "মন্দ" বলে মনে করেন) এবং রায় দিন যে এটি কোনও পর্যবেক্ষক ধরণ নয়। সুতরাং, এটি যেভাবে কাজ করে তা হ'ল প্লাগেবল নামে লুক্কায়িত খালি ক্লাস, এতে কুকুর শ্রেণি দ্বারা ব্যবহৃত পদ্ধতি এবং বৈশিষ্ট্য নেই। সুতরাং, যেহেতু এটি ঘটে, যাদু পদ্ধতিগুলি আমাদের জন্য জড়িত। সে কারণেই 3 এবং 4 অংশে আমরা প্লাগেবল ক্লাস থেকে প্রাপ্ত বস্তুর সাথে গোলমাল করি, কুকুরের ক্লাস নিজেই নয়। পরিবর্তে, আমরা প্লাগিন ক্লাসটি আমাদের জন্য কুকুর অবজেক্টটিতে "স্পর্শ" করতে দিন। (যদি এটি কোনও ধরণের ডিজাইনের প্যাটার্ন আমি জানি না তবে - দয়া করে আমাকে জানান))


3
এ কি সাজসজ্জা নয়?
এমভি


35

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

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

আমার কাছ থেকে kdeloach করতে +1।


25

এখানে আমি ব্যবহার করেছি এমন একটি পদ্ধতির, এটি কিউটি সংকেত / স্লট প্রক্রিয়া, এক ধরণের পর্যবেক্ষক নিদর্শন থেকে অনুলিপি করার চেষ্টা। বস্তু সংকেত নির্গত করতে পারে। প্রতিটি সংকেত সিস্টেমে একটি আইডি থাকে - এটি প্রেরকের আইডি + অবজেক্টের নাম দ্বারা রচিত হয় প্রতিটি সংকেত রিসিয়ারগুলিতে আবদ্ধ করা যায়, যা কেবল "কলযোগ্য" আপনি যখন কোনও বাসায় ক্লাস ব্যবহার করেন তখন সেগুলি পেতে আগ্রহী কারও কাছে সিগন্যালগুলি পাস করতে পারেন When ঘটে, আপনি একটি সংকেত "প্রেরণ"। নীচে এবং উদাহরণ বাস্তবায়ন

    <?php

class SignalsHandler {


    /**
     * hash of senders/signals to slots
     *
     * @var array
     */
    private static $connections = array();


    /**
     * current sender
     *
     * @var class|object
     */
    private static $sender;


    /**
     * connects an object/signal with a slot
     *
     * @param class|object $sender
     * @param string $signal
     * @param callable $slot
     */
    public static function connect($sender, $signal, $slot) {
        if (is_object($sender)) {
            self::$connections[spl_object_hash($sender)][$signal][] = $slot;
        }
        else {
            self::$connections[md5($sender)][$signal][] = $slot;
        }
    }


    /**
     * sends a signal, so all connected slots are called
     *
     * @param class|object $sender
     * @param string $signal
     * @param array $params
     */
    public static function signal($sender, $signal, $params = array()) {
        self::$sender = $sender;
        if (is_object($sender)) {
            if ( ! isset(self::$connections[spl_object_hash($sender)][$signal])) {
                return;
            }
            foreach (self::$connections[spl_object_hash($sender)][$signal] as $slot) {
                call_user_func_array($slot, (array)$params);
            }

        }
        else {
            if ( ! isset(self::$connections[md5($sender)][$signal])) {
                return;
            }
            foreach (self::$connections[md5($sender)][$signal] as $slot) {
                call_user_func_array($slot, (array)$params);
            }
        }

        self::$sender = null;
    }


    /**
     * returns a current signal sender
     *
     * @return class|object
     */
    public static function sender() {
        return self::$sender;
    }

}   

class User {

    public function login() {
        /**
         * try to login
         */
        if ( ! $logged ) {
            SignalsHandler::signal(this, 'loginFailed', 'login failed - username not valid' );
        }
    }

}

class App {
    public static function onFailedLogin($message) {
        print $message;
    }
}


$user = new User();
SignalsHandler::connect($user, 'loginFailed', array($Log, 'writeLog'));
SignalsHandler::connect($user, 'loginFailed', array('App', 'onFailedLogin'));

$user->login();

?>

18

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

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


আপনার নজরদারি করা সিস্টেমগুলির তালিকায় আমি ডোকউইকি যুক্ত করব। এটিতে একটি দুর্দান্ত ইভেন্ট সিস্টেম রয়েছে যা সমৃদ্ধ প্লাগইন ইকোসিস্টেমের অনুমতি দেয়।
chiborg

15

ইয়াহুতে ম্যাট জ্যান্ডস্ট্রার স্টিকলব্যাক নামে একটি ঝরঝরে প্রকল্প রয়েছে যা পিএইচপি-তে প্লাগিনগুলি পরিচালনা করার জন্য বেশিরভাগ কাজ পরিচালনা করে।

এটি একটি প্লাগইন শ্রেণীর ইন্টারফেস প্রয়োগ করে, একটি কমান্ড লাইন ইন্টারফেস সমর্থন করে এবং উঠে আসা এবং চালানো খুব কঠিন নয় - বিশেষত যদি আপনি পিএইচপি আর্কিটেক্ট ম্যাগাজিনে এটি সম্পর্কে কভার স্টোরিটি পড়েন ।


11

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

পার্সি-জাতির প্রাচীন শাস্ত্রগ্রন্থ ফ্রেমওয়ার্ক অনেক hooking পদ্ধতি ব্যবহার করে তোলে, এবং খুব সুন্দরভাবে architected করা হয়। এটি দেখতে একটি ভাল সিস্টেম হবে।


8

আমি অবাক হই যে এখানে বেশিরভাগ উত্তরগুলি ওয়েব অ্যাপ্লিকেশনে স্থানীয় যে প্লাগইনগুলি, যেমন স্থানীয় ওয়েব সার্ভারে চলমান প্লাগইনগুলি সম্পর্কে সজ্জিত বলে মনে হয়।

আপনি যদি প্লাগইনগুলি কোনও অন্য - দূরবর্তী - সার্ভারে চালিত করতে চান তবে কী হবে? এটি করার সর্বোত্তম উপায় হ'ল এমন একটি ফর্ম সরবরাহ করা যা আপনাকে বিভিন্ন ইউআরএল সংজ্ঞায়িত করতে দেয় যা আপনার অ্যাপ্লিকেশনটিতে যখন নির্দিষ্ট ইভেন্টগুলি ঘটে তখন ডাকা হবে।

সবেমাত্র ঘটে যাওয়া ইভেন্টের ভিত্তিতে বিভিন্ন ইভেন্ট বিভিন্ন তথ্য প্রেরণ করবে।

এইভাবে, আপনি কেবলমাত্র আপনার অ্যাপ্লিকেশনটিতে সরবরাহ করা ইউআরএল (যেমন, https এর উপরে) একটি সিআরএল কল সম্পাদন করবেন যেখানে দূরবর্তী সার্ভারগুলি আপনার অ্যাপ্লিকেশন দ্বারা প্রেরিত তথ্যের উপর ভিত্তি করে কার্য সম্পাদন করতে পারে।

এটি দুটি সুবিধা সরবরাহ করে:

  1. আপনাকে আপনার স্থানীয় সার্ভারে কোনও কোড হোস্ট করতে হবে না (সুরক্ষা)
  2. কোডটি তখন অন্য পিএইচপি (বহনযোগ্যতা) অন্যান্য ভাষায় দূরবর্তী সার্ভারগুলিতে (এক্সটেনসিবিলিটি) হতে পারে

8
এটি একটি "প্লাগইন" সিস্টেমের চেয়ে একটি "পুশ এপিআই" এর বেশি - আপনি অন্যান্য পরিষেবার জন্য নির্বাচিত ইভেন্টগুলির বিজ্ঞপ্তি পাওয়ার জন্য একটি উপায় সরবরাহ করছেন। সাধারণত "প্লাগইনস" বলতে যা বোঝায় তা হ'ল আপনি অ্যাপ্লিকেশনটি ইনস্টল করতে পারেন এবং তার আচরণের উদ্দেশ্যে আপনার উদ্দেশ্যগুলিতে কাস্টমাইজ করতে কার্যকারিতা যুক্ত করতে পারেন, যার জন্য স্থানীয়ভাবে প্লাগইনটি চলমান দরকার - বা কমপক্ষে একটি সুরক্ষিত এবং দক্ষ দ্বি-পথ যোগাযোগ থাকতে পারে তথ্য থেকে আবেদন শুধু এটা নিতে থেকে এটা। দুটি বৈশিষ্ট্য কিছুটা স্বতন্ত্র এবং অনেক ক্ষেত্রে একটি "ফিড" (যেমন আরএসএস, আইকল) একটি পুশ এপিআইয়ের একটি সহজ বিকল্প।
আইএমএসওপি
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.