مدرسة السحر PHP

ما هو السحر في PHP؟ هذا يعني عادةً أساليب مثل _construct() أو __get() . الأساليب السحرية في PHP هي ثغرات تساعد المطورين على القيام بأشياء مذهلة. الشبكة مليئة بالتعليمات الخاصة باستخدامها ، والتي ربما تكون مألوفًا لديك. لكن ماذا لو قلنا أنك لم ترَ السحر الحقيقي؟ بعد كل شيء ، كلما بدا لك أنك تعرف كل شيء ، كلما زاد استغرابك عن السحر.



دعونا إسقاط الإطار المعمول به من قواعد OOP وجعل المستحيل ممكنا في مدرسة PHP من السحر. المعلم السحري الرئيسي والأول للمدرسة هو ألكسندر ليساتشينكو ( NightTiger ). سيقوم بتدريس التفكير السحري ، وربما تحب الأساليب السحرية ، والطرق غير القياسية للوصول إلى الخصائص ، وتغيير السياقات ، والبرمجة الموجهة نحو الجانب ، ومرشحات الدفق.


ألكسندر ليساتشينكو هو رئيس قسم تطوير الويب والهندسة المعمارية في الباري. المؤلف والمطور الرئيسي للإطار الموجه جانبًا Go! AOP . متحدث في المؤتمرات الدولية على PHP.

في الفيلم الجيد "وهم الخداع" هناك عبارة:
"كلما اقتربت ، قل ما تراه".

يمكن قول الشيء نفسه عن PHP ، كخدعة سحرية تتيح لك القيام بأشياء غير عادية. ولكن أولاً وقبل كل شيء ، تم إنشاؤه لخداعك: "... إجراء يهدف إلى الخداع ، إما كوسيلة لخداع شخص ما ، أو كنكتة أو شكل من أشكال الترفيه."

إذا أخذنا PHP معًا وحاولنا كتابة شيء سحري عليه ، فمن المرجح أن أخدعك. سأفعل بعض الحيل ، وسوف تتساءل لفترة طويلة لماذا يحدث هذا. ذلك لأن لغة PHP هي لغة برمجة معروفة بأشياءها غير العادية.

المعدات السحرية


ماذا نحتاج من المعدات السحرية؟ طرق مألوفة مؤلمة.

__construct(), __destruct(), __clone(),
__call(), __callStatic(),
__get(), __set(), __isset(), __unset(),
__sleep(), __wakeup(),
__toString(), __invoke(), __set_state(),
__debugInfo()


سألاحظ الطريقة الأخيرة بشكل منفصل - مع ذلك يمكنك كرنك أشياء غير عادية. لكن هذا ليس كل شيء.

  • declare(ticks=1) .
  • debug_backtrace() . هذا هو رفيقنا لفهم أين نحن في الكود الحالي ، لمعرفة من اتصل بنا ولماذا ، مع أي الحجج. من المفيد أن تقرر عدم اتباع كل المنطق.
  • unset(), isset() . يبدو أنه لا يوجد شيء خاص ، لكن هذه التصاميم تخفي الكثير من الحيل ، والتي سننظر فيها أكثر.
  • by-reference passing . عندما نمر بعض الأشياء أو المتغيرات بالرجوع إليها ، يجب أن نتوقع حدوث بعض السحر لا محالة لك.
  • bound closures . على الإغلاق وحقيقة أنها يمكن أن تربط ، يمكنك بناء الكثير من الحيل.
  • تساعد واجهة برمجة تطبيقات Reflection على الارتداد إلى مستوى جديد.
  • StreamWrapper API.

الجهاز جاهز - سأذكر القاعدة الأولى للسحر.

كن دائما أذكى رجل في الغرفة.

خدعة # 1. مقارنة مستحيلة


لنبدأ بالخدعة الأولى التي أسميها "المقارنة المحتملة".
ألق نظرة فاحصة على الكود ومعرفة ما إذا كان هذا يمكن أن يحدث في PHP.



هناك متغير ، نعلن قيمته ، ثم فجأة لا يساوي نفسه.

لا واحد في عدد


هناك قطعة أثرية سحرية مثل NaN - ليس رقمًا.



ميزتها المدهشة هي أنها لا تساوي نفسها. وهذه هي خدعتنا الأولى: استخدم NaN في لغز صديق. لكن NaN ليس هو الحل الوحيد لهذه المهمة.

نحن نستخدم الثوابت




الحيلة هي أننا يمكن أن نعلن false كما هو true بالنسبة namespace والمقارنة. سيتعجب المطور سيئ الحظ لفترة طويلة من وجود سبب true وليس false .

معالج


الخدعة التالية هي مدفعية أقوى من الخيارين السابقين. دعونا نرى كيف يعمل.



تستند الخدعة إلى tick_function ، وكما ذكرت ، declare(ticks=1) .

كيف يعمل كل شيء خارج الصندوق؟ أولاً ، نعلن بعض الوظائف ، وبالرجوع إليها تأخذ المعلمة isMagic ، ثم تحاول تغيير هذه القيمة إلى true . بعد إعلاننا declare(ticks=1) ، يقوم مترجم PHP بعد كل عملية تشغيل أساسية باستدعاء register_tick_function - رد الاتصال. في رد الاتصال هذا ، يمكننا تغيير القيمة التي كانت false مسبقًا إلى true . السحر!

خدعة # 2. تعبيرات سحرية


خذ مثالاً يتم فيه الإعلان عن متغيرين. واحد منهم false ، والآخر true . isBlack و isWhite و var_dump النتيجة. ما رأيك ستكون النتيجة؟



مشغلي الأولوية . الإجابة الصحيحة false ، لأنه في PHP يوجد شيء مثل "أسبقية المشغل".



والمثير للدهشة أن المشغل المنطقي or أولوية أقل من عملية التعيين. لذلك ، يحدث ببساطة تعيين false . في isWhite يمكن أن يكون isWhite أي تعبير آخر سينفذ في حالة فشل الجزء الأول.

تعبيرات سحرية


ألقِ نظرة على الكود أدناه. هناك بعض الصفوف التي تحتوي على المنشئ ، وبعض المصانع ، والتي سيكون رمزها أكثر.



انتبه إلى السطر الأخير.

 $value = new $factory->build(Foo::class); 

هناك العديد من الخيارات التي يمكن أن تحدث.

  • سيتم استخدام $factory كاسم الفئة new ؛
  • سيكون هناك خطأ في التحليل.
  • سيتم استخدام المكالمة $factory->build() ، والقيمة التي ستعود بها هذه الوظيفة ، ستكون النتيجة new ؛
  • سيتم استخدام قيمة $factory->build الممتلكات لبناء الفئة.

دعونا تحقق من الفكرة الأخيرة. في فئة $factory ، نعلن سلسلة من الوظائف السحرية. سوف يكتبون ما نقوم به: استدعاء الخاصية ، استدعاء الأسلوب ، أو حتى محاولة استدعاء invoke على الكائن.

 class Factory { public function _get($name) {echo "Getting property {$name}"; return Foo::class;} public function _call($name, $arg) {echo "Calling method {$name}"; return Foo::class;} public function _invoke($name) {echo "Invoking {$name}"; return Foo::class;} } 

الجواب الصحيح: نحن لا ندعو طريقة ، ولكن خاصية. بعد $factory->build هناك معلمة للمنشئ ، والتي سننتقل إلى هذه الفئة.

بالمناسبة ، في هذا الإطار ، قمت بتطبيق ميزة تسمى "اعتراض إنشاء كائنات جديدة" - يمكنك "قفل" هذا التصميم.

محلل الثغرة


المثال التالي مخصص لمحلل PHP نفسه. هل سبق لك أن حاولت استدعاء وظائف أو تعيين المتغيرات داخل الأقواس المتعرجة؟



حصلت على هذه الخدعة على Twitter ، وهي تعمل بشكل غير قياسي للغاية.

 $result = ${'_' . !$_=getCallback()}(); $_=getCallback(); // string(5) "hello" !$_=getCallback()}(); // bool(false) '_'.!$_=getCallback()}(); // string(1) "_" ${'_'.!$_=getCallback()}(); // string(5) "hello" 

أولاً ، نخصص قيمة التعبير للمتغير المسمى _ (الشرطة السفلية). لدينا بالفعل متغير ، ونحن نحاول عكس قيمته منطقيا ، ونحن false - الخط مصبوب كما لو كان true . ثم نلصقها جميعًا معًا في اسم المتغير ، ومن ثم ننتقل إلى داخل الأقواس المعقوفة.

ما هو السحر؟ هذا ترفيه يسمح لنا أن نشعر بالإلهام وغير العادي ، ويقول: "ماذا؟ لذلك كان ذلك ممكنا؟ "

خدعة # 3. كسر القواعد


ما يعجبني في PHP هو أنه يمكنك كسر القواعد التي ينشئها الجميع في محاولة لتكون آمنة للغاية. هناك تصميم يسمى "الطبقة المختومة" التي تحتوي على مُنشئ خاص. مهمتك كطالب الساحر هي إنشاء مثيل لهذه الفئة.



النظر في ثلاثة خيارات لكيفية القيام بذلك.

الحل


الطريقة الأولى هي الأكثر وضوحا. يجب أن يكون مألوفًا لكل مطور - هذا هو واجهة برمجة التطبيقات القياسية التي توفرها لنا اللغة.



يسمح لك بناء newInstanceWithoutConstructor بتجاوز قيود اللغة التي newInstanceWithoutConstructor المنشئ خاصًا وإنشاء مثيل للفئة لتتجاوز جميع إعلانات المنشئ الخاصة.

الخيار يعمل ، بسيط ، لا يتطلب أي تفسير.

ماس كهربائى


الخيار الثاني يتطلب المزيد من الاهتمام والمهارة. يتم إنشاء وظيفة مجهولة المصدر ، والتي ترتبط بعد ذلك بأوسبري تلك الفئة.



نحن هنا داخل الفصل ويمكننا الاتصال بأمان بالطرق الخاصة. نحن نستخدم هذا من خلال استدعاء new static من سياق فئتنا.



Deserializing


الخيار الثالث هو الأكثر تقدما ، في رأيي.



إذا كتبت سطرًا محددًا بتنسيق معين ، فاستبدل قيمًا معينة هناك - ستنتهي فئتنا.



بعد إلغاء التسلسل ، نحصل على مثالنا.

عقيدة / حزمة مقلد


غالبًا ما يصبح Magic إطارًا أو مكتبة موثقة - على سبيل المثال ، في المذهب / المقلد ، يتم تنفيذ كل هذا. يمكننا إنشاء أي كائنات مع أي رمز.

 composer show doctrine/instantiator --all name : doctrine/instantiator descrip. : A small, lightweight utility to instantiate objects in PHP without invoking their constructors keywords : constructor, instantiate type : library license : MIT License (MIT) 

خدعة # 4. اعتراض وصول الممتلكات


تتجمع السحب: الصف سري ، والخصائص والبناء خاصة ، وكذلك رد الاتصال.

 class Secret { private $secret = 42; private function _construct() { echo 'Secret is: ', $this->secret; } private function onPropAccess(string $name) { echo "Accessing property {$name}"; return 100500; } } // How to create a secret instance and intercept the secret value? 

مهمتنا ، كالمعالجات ، هي استدعاء رد الاتصال بطريقة أو بأخرى.

مضيفا السحر ...


إضافة قليل من السحر لجعلها تعمل.



هذا السؤال من السحر هو getter السحرية. إنها تستدعي وظيفة ، وحتى الآن لم يحدث شيء فظيع. لكننا سنستخدم الخدعة السابقة وننشئ مثيلًا لهذا الكائن يتخطى الإنشاء الخاص.



الآن نحن بحاجة إلى استدعاء رد الاتصال بطريقة أو بأخرى.

"إلغاء" داخل الدائرة


للقيام بذلك ، إنشاء إغلاق. داخل الإغلاق الموجود في نطاق الفصل الدراسي ، نحذف هذا المتغير بوظيفة unset() .



تتيح لك ميزة " unset استبعاد متغير مؤقتًا ، مما سيتيح استدعاء طريقة get السحر لدينا.

نحن نسمي المنشئ الخاص


نظرًا لأن لدينا مُنشئًا خاصًا يعرض echo ، يمكنك فقط الحصول على هذا المنشئ ، وجعله متاحًا عن طريق الاتصال به.



لذلك انهارت صفتنا السرية إلى قطع.



تلقينا رسالة مفادها أننا:

  • اعتراض.
  • عاد شيء مختلف تماما.

leedavis / altr-ego package


تم توثيق الكثير من السحر بالفعل. حزمة altr-ego تتظاهر فقط بأنها مكونك .

 composer show leedavis81/altr-ego --all name : leedavis81/altr-ego descrip. : Access an objects protected / private properties and methods keywords : php, break scope versions : dev-master, v1.0.2, v1.0.1, v1.0.0 type : library license : MIT License (MIT) 

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

خدعة # 5. كائنات ثابتة في PHP


هل هناك كائن غير قابل للتغيير في PHP؟ نعم ، ووقت طويل جدًا.

 namespace Magic { $object = (object) [ "\0Secret\0property" => 'test' ]; var_dump($object); } 

مجرد الحصول عليها بطريقة مثيرة للاهتمام. الشيء المثير للاهتمام هو أننا نخلق مجموعة تحتوي على مفتاح خاص . إنه يبدأ بالبناء \0 - هذا حرف صفر بايت ، وبعد Secret نرى أيضًا \0 .

يستخدم البناء في PHP لإعلان الملكية الخاصة داخل الفصل. إذا حاولنا إرسال كائن إلى صفيف ، فسنرى نفس المفاتيح. لن يكون لدينا شيء سوى stdClass . أنه يحتوي على خاصية خاصة من الفئة Secret ، والتي تساوي test .

 object(stdClass) [1] private 'property' (Secret) => string 'test' (length=4) 

المشكلة الوحيدة هي - إذن لا يمكنك الحصول على هذه الخاصية من هناك. تم إنشاؤه ، ولكن غير متوفر.

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

لنبدأ بأخرى بسيطة - قم بإنشاء DTO ومحاولة اعتراض جميع الخصائص الموجودة فيه (انظر الخدعة السابقة).

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

نحن نقدم طريقة سحرية حتى تتمكن من قراءة هذه القيمة. للقيام بذلك ، لدينا طرق سحرية ، وطرق إصدار سحرية تسمح لنا بتوفير واجهات برمجة التطبيقات.

دعنا نعود إلى مكان موثوق به ومحاولة البحث.

  • Global variables إلغاء Global variables - يمكن لأي شخص تغييرها.
  • Public properties أيضا ليست مناسبة.
  • Protected properties هكذا ، لأن الفئة الفرعية ستتحقق.
  • Private properties . لا توجد ثقة ، لأنه من خلال الإغلاق أو من خلال reflection يمكن تغييره.
  • يمكن Private static properties ، لكن reflection تنكسر أيضًا.

يبدو أنه لا يوجد مكان لإخفاء قيم المتغيرات. ولكن كان هناك شيء سحري - Static variables in functions - هذه متغيرات موجودة بوظائف داخلية.

تخزين آمن للقيم


سألت نيكيتا بوبوف وجاي واتكينز عن ذلك على قناة Stack Overflow الخاصة.



هذه دالة يتم فيها الإعلان عن متغير ثابت. هل من الممكن الخروج منه بطريقة ما؟ الجواب هو لا.

لقد وجدنا ثغرة صغيرة في العالم الآخر من المتغيرات المحمية ونريد استخدامها.

تمرير القيم عن طريق الرابط


سوف نستخدمها بشكل غير قياسي كخاصية للكائن. لكن لا يمكنك تمرير خاصية ، لذلك نستخدم النقل التقليدي للقيم بالرجوع إليها.



اتضح أن هناك فئة فيها طريقة callStatic سحرية ، ويتم الإعلان عن المتغير Static فيها. في أي استدعاء لبعض الوظائف ، نقوم بتمرير قيمة المتغير من الكائن غير القابل للتغيير بالرجوع إلى جميع أساليبنا المتداخلة. لذلك نحن نوع من توفير السياق.

حفظ الدولة


دعونا نرى كيف يتم حفظ الدولة.



انها بسيطة جدا. بالنسبة للكائن المنقول ، نستخدم الدالة spl_object_id ، والتي تقوم بإرجاع معرف منفصل لكل مثيل. State التي حصلنا عليها بالفعل من الكائن تحاول إنقاذ هناك. لا شيء خاص.

تطبيق حالة الكائن


هنا مرة أخرى ، هناك بنية لتمرير القيم حسب خصائص المرجع unset . قمنا بإلغاء تعيين جميع الخصائص الحالية ، بعد حفظها مسبقًا في متغير الحالة ، وتعيين هذا السياق للكائن. لم يعد الكائن يحتوي على أي خصائص ، ولكن فقط معرفه ، والذي تم تعريفه باستخدام spl_object_id ومرفق بهذا الكائن بينما لا يزال قيد الحياة.



الحصول على الدولة


ثم كل شيء بسيط.



نحصل على هذا السياق على الساحر السحري وندعو ممتلكاتنا منه. الآن لا أحد ولا شيء يمكن أن يغير القيمة بعد توصيل هذه Trait .



يتم تجاوز جميع الأساليب السحرية وتنفيذ ثبات الكائن.



lisachenko / كائن غير قابل للتغيير


كما هو متوقع ، كل شيء على الفور رسمي في المكتبة وجاهزة للاستخدام.

 composer show /immutable-object --all name : /immutable-object descrip. : Immutable object library keywords : versions : * dev-master type : library license : MIT License (MIT) 

المكتبة تبدو بسيطة جدا. نحن توصيله وخلق فصلنا. لها خصائص مختلفة: خاصة ، محمية وعامة. نحن نربط ImmutableTrait .



بعد ذلك ، يمكنك بدء الكائن مرة واحدة - انظر قيمته. حقا يتم حفظها هناك ، ويبدو وكأنه DTO حقيقي.

 object (MagicObject) [3] public 'value' => int 200 

ولكن إذا حاولنا تغييره ، على سبيل المثال ، مثل هذا ...



... ثم الحصول على fatal exception على الفور. لا يمكننا تغيير خاصية لأنها غير قابلة للتغيير. كيف ذلك؟



إذا اشتركت في تحدٍ مثير وحاولت تصحيحه ، فستحصل على ما يلي.



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

خدعة # 6. معالجة الموضوع


النظر في التصميم.

 include 'php://filter/read=string.toupper/resource=magic.php'; 

هناك شيء سحري: مرشح PHP ، read ، في النهاية يتم توصيل نوع من ملفات magic.php. هذا الملف يبدو بسيطا جدا.

 <?php echo 'Hello, world!' 

لاحظ أن القضية مختلفة. ومع ذلك ، إذا قمنا "بتعبئة" الملف من خلال تصميمنا ، فسنحصل على هذا:

 HELLO, WORLD! 

ماذا حدث في تلك اللحظة؟ يتيح لك استخدام بناء مرشح PHP في include أي مرشح ، بما في ذلك مرشح ، لتحليل شفرة المصدر. أنت تدير كل شيء في هذا الكود المصدري. يمكنك إزالة final من الفصول والأساليب ، وجعل الخصائص العامة - أي شيء يمكنك كرنك من خلال هذا الشيء.

يعتمد جزء من إطار جانبي على هذا. عندما يكون الفصل متصلاً ، يقوم بتحليله ويحوله إلى ما سيتم تنفيذه.

خارج المربع في PHP يوجد بالفعل مجموعة كاملة من المرشحات الجاهزة.

 var_dump(stream_get_filters()); array (size=10) 0 => string 'zlib.*' (length=6) 1 => string 'bzip2.*' (length=7) 2 => string 'convert.iconv.*' (length=15) 3 => string ' string.rotl3' (length=12) 4 => string 'string.toupper' (length=14) 5 => string 'string.tolower' (length=14) 6 => string 'string.strip_tags' (length=17) 7 => string 'convert.*' (length=9) 8 => string 'consumed' (length=8) 9 => string 'dechunk' (length=7) 

أنها تسمح لك "zip" المحتوى ، وترجمته إلى حالة كبيرة أو صغيرة.

انتهت الحيل الرئيسية التي أردت إظهارها. الآن دعنا ننتقل إلى جوهر كل شيء يمكنني القيام به - البرمجة الموجهة نحو الجانب.

خدعة # 7. الجانب الموجه البرمجة


انظر إلى هذا الرمز وفكر فيما إذا كان جيدًا أو سيئًا من وجهة نظرك.



يبدو أن الرمز مناسب تمامًا. إنه يتحقق من حقوق الوصول ، ويقوم بإجراء التسجيل ، ويخلق مستخدمًا ، ويستمر ، ويحاول exception .

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



كل شيء آخر: "الاهتمامات الثانوية" أو "الاهتمامات الشاملة" هي وظيفة شاملة لعدة قطاعات.

يجعل OOP التقليدي من المستحيل نسخ جميع هذه الهياكل مع لصق نسخ وإزالتها وإخراجها في مكان ما. هذا سيء لأنه يجب عليك تكراره. أتمنى أن يكون الرمز دائمًا نظيفًا ومرتبًا.



بحيث لا يحتوي على تسجيل (السماح بتطبيقه بطريقة ما) ولا يحتوي على security .



هذا كل شيء ، بما في ذلك قطع الأشجار ...



... وفحص أمني ، ...



... يؤديها بنفسها.

وهذا ممكن.

مسرد "الجانب"


هناك شيء يسمى الجانب. هذا مثال بسيط يتحقق من الأذونات. بفضله ، يمكنك رؤية بعض التعليقات التوضيحية ، والتي يتم تمييزها أيضًا بواسطة البرنامج المساعد لـ PhpStorm. تعلن "الجانب" تعبيرات SQL عن النقاط في التعليمات البرمجية لتطبيق هذا الشرط. أدناه ، على سبيل المثال ، نريد تطبيق إغلاق على جميع الأساليب العامة من فئة خدمة المستخدم.



نحصل على الإغلاق باستخدام طريقة $invocation .



هذا هو نوع من الغلاف في أعلى طريقة reflection ، والذي يحتوي على المزيد من الوسائط.

علاوة على ذلك ، في هذا رد الاتصال لكل طريقة ، يمكنك التحقق من حقوق الوصول الضرورية ، وهذا ما يسمى "المشورة".



نقول نوعًا ما اللغة: "عزيزي PHP ، يرجى تطبيق هذه الطريقة قبل كل مكالمة على الطريقة العامة من فئة خدمة المستخدم" UserService سطر واحد فقط ، ولكن الكثير من المفيد.

الجانب مقابل الحدث المستمع


لجعله أكثر وضوحًا ، قمت بإجراء مقارنة بين Aspect و Event Listener. يعمل الكثيرون في Symfony ويعرفون ما هو Event Dispatcher.



إنها متشابهة في أننا نعتمد نوعًا من التبعية ، على سبيل المثال ، AutorizationChecker ، ونعلن مكان التقديم في هذه الحالة. في حالة المستمع ، هو برنامج SubscrabingEvent يسمى UserCreate ، وفي حالة Aspect نحن نشترك في جميع استدعاءات الطرق العامة من UserService .في الوقت نفسه ، يكون محتوى معالج رد الاتصال نفسه هو نفسه تقريبًا: نحن نتحقق من شيء ونتفاعل وفقًا لذلك.

النظر في كيفية عمل كل شيء تحت غطاء محرك السيارة.

الخطوة الأولى التي يتطلبها إطار جانبي هي التسجيل Aspects .



المرحلة الثانية . للتعامل مع هذا ، يتم استخدام الحيلة السابقة مع مرشح PHP مرة أخرى .



هذا مكون خاص يحول شفرة المصدر. يقوم بذلك سراً ، لكنه سيعمل جيدًا في الإنتاج ، لأنه متكامل مع OPcache.

المرحلة الثالثة . تم دمج كل شيء على المستوى Composer. بمجرد تثبيت Go! AOP ، وقال انه يبدأ التواصل عن كثبComposer , .



Aspects , Aspects . .

.

PHP-Parser . , , . , , PHP-Parser . .



. , goaop/parser-reflection .



AST- , . , , , .

.



, , Aspect .



, .



, , . — , - , .



, . , .

Aspect MOCK. «», , . .

joinPoint . - joinPoint : , , .

ما التالي؟


.

OPcache preloading for AOP Core . AOP- . 10 . Bootstrapping , PHP.

FFI integration to modify binary opcodes . , , . PHP-opcodes, .bin . FFI .

Modifying PHP engine internal callbacks PHP- userland. PHP . FFI PHP userland, , , . .

, .

#8. goaop/framework


, GitHub .

 composer show goaop/framework --all name : goaop/framework descrip. : Framework for aspect-oriented programming in PHP. keywords : php, aop, library, aspect versions : dev-master, 3.0.x-dev, 2.x-dev, 2.3.1, … type : library license : MIT License 

, PhpStorm.



, Pointcuts. , , . — , , .

Trick #9.


. , .

: , - . fastcgi_finish_request . , , , - callback — .

?

, Deffered , , .



Aspect , , , Deffered , .



Aspect : , , , callback, , callback. .

React , promise . , - , - , .

, .



shutdown_function Aspect . , callback, , , , callback onPhpTerminate . fastcgi_finish_request : «, , , , ». .

, sendPushNotification .



, - — 2 .



, , , 2 .

, Deferred .



, . - , , .

هذا كل شيء. , - . , .

PHP Russia 2020 . — . telegram- , PHP Russia 2020.

Source: https://habr.com/ru/post/ar478618/


All Articles