PHP अनुप्रयोग के लिए प्लगइन्स को अनुमति देने का सबसे अच्छा तरीका

मैं PHP में एक नया वेब एप्लिकेशन शुरू कर रहा हूं और इस बार मैं कुछ ऐसा बनाना चाहता हूं जो लोग प्लगइन इंटरफ़ेस का उपयोग करके विस्तार कर सकें।

कोई अपने कोड में 'हुक' लिखने के बारे में कैसे जाता है ताकि प्लगइन्स विशिष्ट घटनाओं से जुड़ सकें?

0
जोड़ा संपादित
विचारों: 13

8 उत्तर

आप एक पर्यवेक्षक पैटर्न का उपयोग कर सकते हैं। इसे पूरा करने के लिए एक सरल कार्यात्मक तरीका:

<?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

नोट:

इस उदाहरण स्रोत कोड के लिए, आपको अपने सभी प्लगइन को वास्तविक स्रोत कोड से पहले घोषित करना होगा जिसे आप विस्तारित करना चाहते हैं। मैंने प्लगइन में एकल या एकाधिक मानों को पारित करने के तरीके का एक उदाहरण शामिल किया है। इसका सबसे कठिन हिस्सा वास्तविक दस्तावेज लिख रहा है जो बताता है कि प्रत्येक हुक में कौन से तर्क पारित किए जाते हैं।

यह PHP में प्लगइन सिस्टम को पूरा करने का सिर्फ एक तरीका है। बेहतर विकल्प हैं, मेरा सुझाव है कि आप अधिक जानकारी के लिए वर्डप्रेस दस्तावेज़ीकरण देखें।

क्षमा करें, ऐसा लगता है कि अंडरस्कोर वर्णों को मार्कडाउन द्वारा HTML इकाइयों द्वारा प्रतिस्थापित किया गया है? जब यह बग ठीक हो जाता है तो मैं इस कोड को दोबारा पोस्ट कर सकता हूं।

संपादित करें: कभी नहीं, यह केवल तब दिखाई देता है जब आप संपादन कर रहे हैं

0
जोड़ा
पेडेंटिक नोट: यह पर्यवेक्षक पैटर्न का एक उदाहरण नहीं है। यह मध्यस्थ पैटर्न का एक उदाहरण है। सच्चे पर्यवेक्षक पूरी तरह से अधिसूचनाएं हैं, कोई संदेश पास या सशर्त अधिसूचना नहीं है (न ही अधिसूचनाओं को नियंत्रित करने के लिए केंद्रीय प्रबंधक है)। यह जवाब गलत नहीं बनाता है, लेकिन लोगों को गलत नाम से कॉल करने वाले लोगों को रोकने के लिए ध्यान दिया जाना चाहिए ...
जोड़ा लेखक ircmaxell, स्रोत
ध्यान दें कि PHP> = 5.0 के लिए आप एसपीएल में परिभाषित पर्यवेक्षक / विषय इंटरफेस का उपयोग करके इसे कार्यान्वित कर सकते हैं: php.net/manual/en/class.splobserver.php
जोड़ा लेखक John Carter, स्रोत
ध्यान दें कि एकाधिक हुक / श्रोताओं का उपयोग करते समय, आपको केवल स्ट्रिंग या सरणी ही वापस करनी चाहिए, दोनों नहीं। मैंने हाउंड सीएमएस के लिए कुछ ऐसा ही कार्यान्वित किया है - getbutterfly.com/hound
जोड़ा लेखक Ciprian, स्रोत

हुक और श्रोता विधि का सबसे अधिक उपयोग किया जाता है, लेकिन अन्य चीजें हैं जो आप कर सकते हैं। आपके ऐप के आकार के आधार पर, और आप किस कोड को देखने के लिए अनुमति दे रहे हैं (यह एक एफओएसएस स्क्रिप्ट, या घर में कुछ) होने पर निर्भर करेगा कि आप प्लगइन को कैसे अनुमति देना चाहते हैं।

kdeloach का एक अच्छा उदाहरण है, लेकिन उसका कार्यान्वयन और हुक फ़ंक्शन थोड़ा असुरक्षित है। मैं आपके लिए आपके लेखन के PHP ऐप की प्रकृति की अधिक जानकारी देने के लिए कहूंगा, और आप प्लगइन को कैसे फ़िट करते हैं।

मेरे से kdeloach करने के लिए +1।

0
जोड़ा

मेरा मानना ​​है कि जेफ की अपनी सलाह का पालन करना सबसे आसान तरीका है और मौजूदा कोड के आसपास एक नज़र डालें। वर्डप्रेस, ड्रूपल, जूमला और अन्य प्रसिद्ध PHP-आधारित CMS को देखने का प्रयास करें ताकि यह देखने के लिए कि उनके एपीआई हुक कैसे दिखते हैं और महसूस करते हैं। इस तरह आप उन विचारों को भी प्राप्त कर सकते हैं जिन्हें आपने पहले कुछ चीजों को थोड़ा और अधिक बनाने के लिए नहीं सोचा था।

एक और सीधा जवाब सामान्य फाइलों को लिखना होगा कि वे अपनी फाइल में "include_once" करेंगे जो उन्हें आवश्यक उपयोगिता प्रदान करेगा। यह श्रेणियों में विभाजित हो जाएगा और एक मैसिव "hooks.php" फ़ाइल में प्रदान नहीं किया जाएगा। हालांकि सावधान रहें, क्योंकि जो हो रहा है वह यह है कि जिन फ़ाइलों में वे शामिल हैं, उनमें अधिक से अधिक निर्भरताएं और कार्यक्षमता में सुधार होता है। एपीआई निर्भरता कम रखने की कोशिश करें। I.E उनके लिए शामिल करने के लिए कम फाइलें।

0
जोड़ा
मैं सिस्टम की सूची में DokuWiki जोड़ूंगा जिसे आप देख सकते हैं। इसमें एक अच्छी घटना प्रणाली है जो एक समृद्ध प्लगइन पारिस्थितिक तंत्र की अनुमति देता है।
जोड़ा लेखक chiborg, स्रोत

तो मान लीजिए कि आप पर्यवेक्षक पैटर्न नहीं चाहते हैं क्योंकि यह आवश्यक है कि आप सुनने के कार्य को संभालने के लिए अपनी कक्षा विधियों को बदल दें, और कुछ सामान्य बनाना चाहते हैं। और मान लीजिए कि आप विस्तार विरासत का उपयोग नहीं करना चाहते हैं क्योंकि आप पहले से ही किसी अन्य वर्ग से अपनी कक्षा में विरासत में हो सकते हैं। किसी भी वर्ग को बिना किसी प्रयास के प्लग करने योग्य बनाने के लिए एक सामान्य तरीका होना अच्छा नहीं होगा ? ऐसे:

<?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
\n"; } public function sayName() { echo "
\nMy Name is: " . $this->Name . "
\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 में, आप अपनी PHP स्क्रिप्ट के शीर्ष पर requ_once() कॉल के साथ शामिल हो सकते हैं। यह कुछ प्लग करने योग्य बनाने के लिए कक्षाओं को लोड करता है।

भाग 2 में, वहीं हम एक वर्ग लोड करते हैं। नोट मुझे कक्षा के लिए विशेष कुछ भी करने की ज़रूरत नहीं है, जो पर्यवेक्षक पैटर्न से काफी अलग है।

भाग 3 में, वहीं हम अपनी कक्षा को "प्लग करने योग्य" होने के लिए स्विच करते हैं (यानी, प्लगइन का समर्थन करता है जो हमें क्लास विधियों और गुणों को ओवरराइड करने देता है)। इसलिए, उदाहरण के लिए, यदि आपके पास कोई वेब ऐप है, तो आपके पास प्लगइन रजिस्ट्री हो सकती है, और आप यहां प्लगइन सक्रिय कर सकते हैं। ध्यान दें Dog_bark_beforeEvent() फ़ंक्शन। यदि मैं रिटर्न स्टेटमेंट से पहले $ मिश्रित = 'BLOCK_EVENT' सेट करता हूं, तो यह कुत्ते को भौंकने से रोक देगा और Dog_bark_afterEvent को भी अवरुद्ध करेगा क्योंकि कोई ईवेंट नहीं होगा।

भाग 4 में, यह सामान्य ऑपरेशन कोड है, लेकिन ध्यान दें कि जो भी आप सोच सकते हैं वह दौड़ना उतना ही नहीं चलता है। उदाहरण के लिए, कुत्ता इसका नाम 'फिडो', लेकिन 'कोको' के रूप में घोषित नहीं करता है। कुत्ता 'मेयो' नहीं कहता है, लेकिन 'वाह'। और जब आप कुत्ते के नाम को बाद में देखना चाहते हैं, तो आपको लगता है कि यह 'कोको' के बजाय 'अलग' है। उन सभी ओवरराइड भाग 3 में प्रदान किए गए थे।

यह कैसे काम करता है? खैर, आइए eval() (जो हर कोई कहता है "बुराई" है) और नियम दें कि यह पर्यवेक्षक पैटर्न नहीं है। तो, जिस तरह से यह काम करता है वह स्नेकी खाली वर्ग है जिसे प्लग्गेबल कहा जाता है, जिसमें कुत्ते वर्ग द्वारा उपयोग की जाने वाली विधियों और गुणों में शामिल नहीं है। इस प्रकार, चूंकि ऐसा होता है, जादू विधियां हमारे लिए संलग्न होंगी। यही कारण है कि भागों 3 और 4 में हम प्लग करने योग्य वर्ग से प्राप्त वस्तु के साथ गड़बड़ करते हैं, न कि कुत्ते वर्ग स्वयं। इसके बजाए, हमने प्लगइन क्लास को हमारे लिए डॉग ऑब्जेक्ट पर "स्पर्श" करने दिया। (यदि यह किसी प्रकार का डिज़ाइन पैटर्न है, तो मुझे पता नहीं है - कृपया मुझे बताएं।)

0
जोड़ा
मैं इस बारे में विकिपीडिया पर पढ़ता हूं और, वाह, आप सही हैं! :)
जोड़ा लेखक Volomike, स्रोत
क्या यह एक सजावटी नहीं है?
जोड़ा लेखक MV., स्रोत

यहां एक दृष्टिकोण है जिसका मैंने उपयोग किया है, यह क्यूटी संकेत / स्लॉट तंत्र, एक प्रकार का पर्यवेक्षक पैटर्न से प्रतिलिपि बनाने का प्रयास है। ऑब्जेक्ट सिग्नल उत्सर्जित कर सकते हैं। प्रत्येक सिग्नल में सिस्टम में एक आईडी होती है - यह प्रेषक के आईडी + ऑब्जेक्ट नाम द्वारा रचित है प्रत्येक सिग्नल रिसीवर को बाध्य किया जा सकता है, जो कि बस एक "कॉल करने योग्य" है आप उन्हें प्राप्त करने में रुचि रखने वाले किसी भी व्यक्ति को सिग्नल पास करने के लिए बस कक्षा का उपयोग करते हैं जब कुछ होता है, तो आप एक संकेत भेजते हैं। नीचे है और उदाहरण कार्यान्वयन

    <?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();

?>
0
जोड़ा

मुझे आश्चर्य है कि यहां के अधिकांश उत्तर प्लगइन के बारे में तैयार हैं जो वेब एप्लिकेशन के लिए स्थानीय हैं, यानी स्थानीय वेब सर्वर पर चलने वाले प्लगइन्स।

क्या आप प्लगइन को एक अलग - रिमोट सर्वर पर चलाने के लिए चाहते थे? ऐसा करने का सबसे अच्छा तरीका एक ऐसा फॉर्म प्रदान करना होगा जो आपको विभिन्न यूआरएल को परिभाषित करने की अनुमति देता है जिसे आपके एप्लिकेशन में विशेष घटनाएं होने पर बुलाया जाएगा।

अलग-अलग घटनाएं बस हुई घटना के आधार पर अलग-अलग जानकारी भेजती हैं।

इस तरह, आप केवल उस यूआरएल पर एक कर्ल कॉल करेंगे जो आपके आवेदन (जैसे https पर) प्रदान किया गया है, जहां दूरस्थ सर्वर आपके आवेदन द्वारा भेजी गई जानकारी के आधार पर कार्य कर सकते हैं।

यह दो लाभ प्रदान करता है:

  1. आपको अपने स्थानीय सर्वर (सुरक्षा)
  2. पर कोई कोड होस्ट करने की आवश्यकता नहीं है
  3. कोड अलग-अलग भाषाओं में PHP (पोर्टेबिलिटी)
  4. में दूरस्थ सर्वर (एक्स्टेंसिबिलिटी) पर हो सकता है
0
जोड़ा
यह "प्लगइन" प्रणाली की तुलना में "पुश एपीआई" से अधिक है - आप अन्य सेवाओं के लिए चयनित घटनाओं की अधिसूचना प्राप्त करने का एक तरीका प्रदान कर रहे हैं। आम तौर पर "प्लगइन्स" का अर्थ यह है कि आप एप्लिकेशन इंस्टॉल कर सकते हैं और उसके बाद अपने उद्देश्यों को अपने व्यवहार को अनुकूलित करने के लिए कार्यक्षमता जोड़ सकते हैं, जिसके लिए प्लगइन को स्थानीय रूप से चलाना आवश्यक है - या कम से कम एक सुरक्षित और कुशल 2-तरफा संचार प्रदान करने के लिए जानकारी से एप्लिकेशन न केवल से इसे लेता है। दो विशेषताएं कुछ हद तक अलग हैं, और कई मामलों में एक "फ़ीड" (जैसे आरएसएस, आईकैल) पुश एपीआई के लिए एक साधा
जोड़ा लेखक IMSoP, स्रोत

याहू पर मैट ज़ैंडस्ट्रा द्वारा स्टिकलेबैक नामक एक साफ परियोजना है PHP में प्लगइन को संभालने के लिए अधिकांश काम।

यह प्लगइन क्लास के इंटरफ़ेस को लागू करता है, कमांड लाइन इंटरफ़ेस का समर्थन करता है और उठने और चलाने में बहुत मुश्किल नहीं है - खासकर यदि आप PHP आर्किटेक्ट पत्रिका ।

0
जोड़ा

अच्छी सलाह यह है कि अन्य परियोजनाओं ने इसे कैसे किया है। कई प्लगइन स्थापित करने के लिए कॉल करते हैं और उनके "नाम" सेवाओं के लिए पंजीकृत होते हैं (जैसे वर्डप्रेस करता है) ताकि आपके कोड में "पॉइंट" हों जहां आप एक ऐसे फ़ंक्शन को कॉल करते हैं जो पंजीकृत श्रोताओं की पहचान करता है और उन्हें निष्पादित करता है। एक मानक ओओ डिजाइन पटर पर्यवेक्षक पैटर्न है, जो कार्यान्वित करने का एक अच्छा विकल्प होगा वास्तव में ऑब्जेक्ट उन्मुख PHP सिस्टम।

ज़ेंड फ्रेमवर्क कई हुकिंग विधियों का उपयोग करता है, और यह बहुत अच्छी तरह से आर्किटेक्टेड है। यह देखने के लिए एक अच्छी प्रणाली होगी।

0
जोड़ा