سؤال

أنا بدأت تطبيق ويب جديد في PHP و هذه المرة كنت ترغب في خلق شيء أن الناس يمكن أن تمتد باستخدام واجهة البرنامج المساعد.

كيف دفعة واحدة حول كتابة 'كلاب' في التعليمات البرمجية الخاصة بهم بحيث الإضافات يمكن أن نعلق على أحداث معينة?

هل كانت مفيدة؟

المحلول

هل يمكن استخدام مراقب نمط.بسيطة وظيفية طريقة لتحقيق ذلك:

<?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 عن طريق تخفيض السعر?لا يمكن إعادة نشر هذا الرمز عندما يكون هذا علة يحصل ثابت.

تحرير:لا يظهر فقط عندما تكون التحرير

نصائح أخرى

لذلك دعونا نقول كنت لا تريد نمط مراقب لأنه يتطلب تغيير إعدادات الطبقة أساليب التعامل مع هذه المهمة من الاستماع و تريد شيئا عامة.و دعونا نقول كنت لا تريد استخدام 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() الاتصال في الجزء العلوي من البرنامج النصي PHP.تحميل دروس لجعل شيء للتوصيل.

في الجزء 2, حيث ان الحمل فئة.ملاحظة أنا لم يكن لديك للقيام بأي شيء خاص إلى الدرجة التي تختلف اختلافا كبيرا من نمط مراقب.

في الجزء 3, حيث ان التبديل طبقتنا حول إلى "التوصيل" (وهذا هو ، يدعم الإضافات التي تتيح لنا تجاوز الدرجة الأساليب والخصائص).لذا, فعلى سبيل المثال, إذا كان لديك تطبيق ويب, قد يكون لديك البرنامج المساعد التسجيل ، يمكنك تفعيل الإضافات هنا.لاحظ أيضا Dog_bark_beforeEvent() وظيفة.إذا كنت تعيين $mixed = 'BLOCK_EVENT' قبل عودة البيان ، فإنه سيتم منع الكلب من النباح و أيضا منع Dog_bark_afterEvent لأنه لن يكون هناك أي الحدث.

في الجزء 4, هذا هو عملية طبيعية رمز ، ولكن لاحظ أن ما قد تعتقد أن تشغيل لا يعمل مثل ذلك على الإطلاق.فعلى سبيل المثال ، فإن الكلب لا يعلن انه اسم 'فيدو', ولكن "كوكو".الكلب لا تقول مياو', لكن 'اللحمة'.و عندما تريد أن ننظر إلى اسم الكلب بعد ذلك ، تجد أنها "مختلفة" بدلا من "كوكو".كل هذه تجاوزات في الجزء 3.

كيف يعمل هذا ؟ حسنا, دعونا نستبعد eval() (التي يقول الجميع هو "الشر") والمادة أنها غير مراقب نمط.لذلك ، فإن الطريقة التي يعمل بها هو متستر فارغة فئة تسمى للتوصيل ، والتي لا تحتوي على الأساليب والخصائص المستخدمة من قبل الكلب الدرجة.وهكذا ، ومنذ ذلك يحدث ، طرق سحرية سوف تشارك بالنسبة لنا.هذا هو السبب في الأجزاء 3 و 4 نحن الفوضى مع كائن مشتق من للتوصيل الدرجة وليس الكلب الطبقة نفسها.بدلا من ذلك, ندع المساعد من الدرجة تفعل "لمس" على الكلب كائن بالنسبة لنا.(إذا كان هذا هو نوع من نمط التصميم أنا لا أعرف عن -- واسمحوا لي أن أعرف.)

على هوك و المستمع الطريقة هي الأكثر شيوعا, ولكن هناك أشياء أخرى يمكنك القيام به.اعتمادا على حجم التطبيق الخاص بك و الذي سوف تسمح نرى رمز (هذا سيكون البرمجيات الحرة والمفتوحة المصدر النصي ، أو أي شيء في البيت) سوف تؤثر إلى حد كبير كيف تريد أن تسمح الإضافات.

kdeloach له مثال ، لكن تنفيذ وربط وظيفة قليلا غير آمنة.وأود أن أطلب منك أن تعطي المزيد من المعلومات عن طبيعة php التطبيق الخاص بك الكتابة ، كيف ترى الإضافات المناسب.

+1 kdeloach مني.

هنا هو نهج لقد استعملت انها محاولة نسخ من Qt إشارات/فتحات آلية نوع من نمط مراقب.الأشياء يمكن أن تنبعث منها إشارات.كل إشارة غير معرف في النظام - انها تتكون من هوية المرسل + اسم الكائن كل إشارة يمكن binded إلى أجهزة الاستقبال ، والتي ببساطة هو "المستحقة" يمكنك استخدام حافلة الدرجة لتمرير إشارات إلى أي شخص مهتم في الحصول عليها عندما يحدث شيء ، "إرسال" إشارة.أدناه هو تنفيذ سبيل المثال

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

?>

أعتقد أن أسهل طريقة لمتابعة جيف الخاصة المشورة وإلقاء نظرة حول التعليمات البرمجية الموجودة.حاول تبحث في وورد, دروبال, جملة و أخرى معروفة استنادا PHP CMS هو أن نرى كيف API الخاصة السنانير الشكل والمظهر.بهذه الطريقة يمكنك حتى الحصول على أفكار قد لا يعتقد سابقا إلى جعل الأمور أكثر قليلا rubust.

أكثر مباشرة سيكون الجواب إلى الكتابة العامة ملفات بأنهم "include_once" إلى الملفات الخاصة بهم التي من شأنها أن توفر سهولة الاستخدام يحتاجونها.هذا من شأنه أن يكون انقسموا إلى فئات و لم تقدم في واحدة ضخمة "hooks.php" الملف.كن حذرا على الرغم لأن ما ينتهي يحدث هو أن الملفات التي تشمل في نهاية المطاف وجود المزيد والمزيد من تبعيات وظائف يحسن.في محاولة للحفاظ على API تبعيات منخفضة.أي أقل ملفات لهم أن تدرج.

هناك مشروع يسمى أنيق أبو شوكة سمك شائك من مات Zandstra في ياهو الذي يعالج الكثير من العمل من أجل التعامل مع الإضافات في PHP.

وهو ما يفرض واجهة البرنامج المساعد الدرجة يدعم واجهة سطر الأوامر و ليس من الصعب جدا الحصول على ما يصل وتشغيل - وخاصة إذا كنت تقرأ قصة الغلاف عن ذلك في PHP مجلة المهندس.

نصيحة جيدة هو أن ننظر كيف مشاريع أخرى قد فعلت ذلك.العديد من الدعوة إلى وجود الإضافات المثبتة و "اسم" مسجل الخدمات (مثل وورد لا) حتى يكون لديك "نقطة" في التعليمات البرمجية الخاصة بك حيث يمكنك استدعاء الدالة التي تحدد المسجلين المستمعين وينفذ لهم.معيار التصميم OO طقطق هو نمط مراقب, الذي من شأنه أن يكون خيارا جيدا لتنفيذ حقا وجوه المنحى PHP النظام.

على الإطار زند يجعل من استخدام العديد من طرق تركيب و هو لطيف جدا بالحلول.أن يكون نظام جيد أن ننظر إلى.

أنا مندهش من أن معظم الإجابات هنا يبدو أن تكون موجهة عن الإضافات المحلية إلى تطبيق ويب ، أي الإضافات التي يتم تشغيلها على ملقم ويب المحلي.

ماذا لو أردت الإضافات تعمل على مختلف - عن الخادم ؟ أفضل طريقة للقيام بذلك هو تقديم شكل يسمح لك لتحديد عناوين مختلفة التي من شأنها أن يسمى عند أحداث معينة تحدث في التطبيق الخاص بك.

مختلف الأحداث إرسال معلومات مختلفة استنادا إلى الأحداث التي حدثت للتو.

بهذه الطريقة, كنت مجرد إجراء حليقة الدعوة إلى URL التي تم تقديمها إلى التطبيق الخاص بك (على سبيل المثال عبر https) حيث الملقمات البعيدة يمكن أن تؤدي المهام استنادا إلى المعلومات التي تم إرسالها من خلال التطبيق الخاص بك.

وهذا يوفر فوائد اثنين:

  1. ليس عليك أن تستضيف أي رمز على الخادم المحلي (الأمن)
  2. رمز يمكن أن يكون على الملقمات البعيدة (التمدد) في لغات مختلفة أخرى ثم PHP (قابلية)
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top