PHP. الساحر تنقيط على علامات اقتباس


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

في هذه المقالة ، سيكون هناك معيار واحد فقط ، حيث سيكون بدونه ، ويتم التركيز بشكل رئيسي على تحليل كيفية ترتيبه بالداخل.

تنصل


  1. كل ما هو موضح أدناه هو ، بالنسبة للجزء الأكبر ، توفير على نانوثانية ، ومن الناحية العملية ، لن يفعل شيئًا سوى خسارة الوقت الضائع في مثل هذا التحليل المصغر. هذا ينطبق بشكل خاص على "تحسينات" من وقت الترجمة.
  2. سأقطع الكود والإخراج إلى أقصى حد ، ولم يتبق منه سوى الجوهر.
  3. عند كتابة مقال ، استخدمت PHP 7.2

التمهيدية اللازمة


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

سيتم تحليل اقتباسات مفردة مثل هذا:

statement -> expr -> scalar -> dereferencable_scalar -> T_CONSTANT_ENCAPSED_STRING 

مضاعفة جدا:

 statement -> expr -> scalar -> '"' encaps_list '"' ->        ,  ,     

في المقالات المتعلقة بـ microoptimizations لـ PHP ، هناك نصيحة غالبًا بعدم استخدام الطباعة ، لأنها أبطأ من الصدى . دعونا نرى كيف يتم فرزها.

تحليل الصدى :

 statement -> T_ECHO echo_expr_list -> echo_expr_list ->  echo_expr -> expr 

تحليل الطباعة :

 statement -> expr -> T_PRINT expr -> expr ( ) 

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

من أجل عدم زيادة الانتباه مرة أخرى أثناء المقال ، سنضع في اعتبارنا أن علامات الاقتباس المزدوجة في مرحلة الترجمة تفقد واحدة ، ويفقد صدى الطباعة . أيضًا ، دعونا لا ننسى أنه في أسوأ الحالات ، يتعلق الأمر بالنانو ثانية.

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

 1 - void zend_compile_print(znode *result, zend_ast *ast) /* {{{ */ 1 + void zend_compile_echo(zend_ast *ast) /* {{{ */ 2 2 { 3 3 zend_op *opline; 4 4 zend_ast *expr_ast = ast->child[0]; 5 5 6 6 znode expr_node; 7 7 zend_compile_expr(&expr_node, expr_ast); 8 8 9 9 opline = zend_emit_op(NULL, ZEND_ECHO, &expr_node, NULL); 10 - opline->extended_value = 1; 11 - 12 - result->op_type = IS_CONST; 13 - ZVAL_LONG(&result->u.constant, 1); 10 + opline->extended_value = 0; 14 11 } 

حسنًا ، أنت تفهم - أنها متطابقة في الوظائف ، ولكن الطباعة تُرجع أيضًا ثابتًا يساوي 1. أعتقد أن هذا الموضوع مع الطباعة يمكنك إغلاقه ونسيانه إلى الأبد.

خط بسيط ، دون زخرفة


سلاسل echo 'Some string'; echo "Some string"; سيتم تقسيم متطابقة تقريبا إلى 2 (إخلاء مسؤولية P2) الرموز.

 T_ECHO: echo T_ENCAPSED_AND_WHITESPACE/T_CONSTANT_ENCAPSED_STRING: "Some string" 

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

ستكون رموز شفرة التشغيل بسيطة ومشوهة تمامًا:

 line #* EIO op fetch ext return operands ----------------------------------------------------------- 4 0 E > ECHO 'Some string' 


النتائج


إذا كنت ترغب في حفظ بضع دورات للمعالج في مرحلة الترجمة ، فاستعمل علامات الاقتباس المفردة للسلاسل الثابتة.

خط ديناميكي


هناك 4 خيارات.

 echo "Hello $name! Have a nice day!"; echo 'Hello '.$name.'! Have a nice day!'; echo 'Hello ', $name, '! Have a nice day!'; printf ('Hello %s! Have a nice day!', $name); 

للخيار الأول:

 T_ECHO: echo T_ENCAPSED_AND_WHITESPACE: Hello T_VARIABLE: $name T_ENCAPSED_AND_WHITESPACE: ! Have a nice day! 

للثانية (للثالثة أيضًا ، فقط بدلاً من الفترات ستكون هناك فواصل):

 T_ECHO: echo T_CONSTANT_ENCAPSED_STRING: 'Hello ' string: . T_VARIABLE: $name string: . T_CONSTANT_ENCAPSED_STRING: '! Have a nice day!' 

للرابع:

 T_STRING: printf T_CONSTANT_ENCAPSED_STRING: 'Hello %s! Have a nice day!' string: , T_VARIABLE: $name 

ولكن مع opcodes سيكون كل شيء أكثر تسلية.

أول واحد:

 echo "Hello $name! Have a nice day!"; line #* EIO op fetch ext return operands ----------------------------------------------------------- 3 0 E > ASSIGN !0, 'Vasya' 4 1 ROPE_INIT 3 ~3 'Hello+' 2 ROPE_ADD 1 ~3 ~3, !0 3 ROPE_END 2 ~2 ~3, '%21+Have+a+nice+day%21' 4 ECHO ~2 

الثانية:

 echo 'Hello '.$name.'! Have a nice day!'; line #* EIO op fetch ext return operands ----------------------------------------------------------- 3 0 E > ASSIGN !0, 'Vasya' 4 1 CONCAT ~2 'Hello+', !0 2 CONCAT ~3 ~2, '%21+Have+a+nice+day%21' 3 ECHO ~3 

الثالث:

 echo 'Hello ', $name, '! Have a nice day!'; line #* EIO op fetch ext return operands ----------------------------------------------------------- 3 0 E > ASSIGN !0, 'Vasya' 4 1 ECHO 'Hello+' 2 ECHO !0 3 ECHO '%21+Have+a+nice+day%21' 

الرابع:

 printf ('Hello %s! Have a nice day!', $name); line #* EIO op fetch ext return operands ----------------------------------------------------------- 3 0 E > ASSIGN !0, 'Vasya' 4 1 INIT_FCALL 'printf' 2 SEND_VAL 'Hello+%25s%21+Have+a+nice+day%21' 3 SEND_VAR !0 4 DO_ICALL 

يخبرنا الفطرة السليمة أن الخيار "printf" سوف يفقد سرعته من خلال الثلاثة الأولى (خاصة أنه في النهاية لا يزال هناك نفس ECHO) ، لذلك سنتركه للمهام التي تتطلب التنسيق ولن نتذكر المزيد في هذه المقالة.

يبدو أن الخيار الثالث هو الأسرع - لطباعة ثلاثة أسطر متتالية دون تسلسل ، و ROPE غريبة وإنشاء متغيرات إضافية. لكن ليس بهذه البساطة. من المؤكد أن وظيفة الطباعة في PHP ليست هي Rocket Science ، ولكنها ليست بأي حال من الأحوال نواتج C-shny عادية. من يهتم - تنكشف الكرة بدءًا من php_output_write في الملف الرئيسي / output.c .

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

ولكن مع ROPE_INIT و ROPE_ADD و ROPE_END ، كل شيء أكثر إثارة للاهتمام. اتبع اليدين:

  1. ROPE_INIT (تحويلة = 3 ، عائد = ~ 3 ، معاملات = "Hello +")
    نحن نخصص "الحبل" من ثلاث فتحات (تحويلة) ، ونضع السلسلة "Hello +" (المعاملات) في الفتحة 0 ونعيد المتغير المؤقت ~ 3 (الرجوع) الذي يحتوي على "الحبل".
  2. ROPE_ADD (تحويلة = 1 ، عائد = ~ 3 ، معاملات = ~ 3 ،! 0)
    نضع في الفتحة 1 (تحويلة) من "الحبل" ~ 3 (المعاملات) السلسلة "Vasya" ، التي تم الحصول عليها من المتغير! 0 (المعاملات) وإرجاع "الحبل" ~ 3 (العودة).
  3. ROPE_END (تحويلة = 2 ، عائد = ~ 2 ، معاملات = ~ 3 ، '٪ 21 + لديك + + + لطيفة + يوم٪ 21')
    نضع السطر '٪ 21 + Have + a + nice + day٪ 21' (المعاملات) في الفتحة 2 (ext) ، ثم نقوم بإنشاء سلسلة متدرجة بالحجم المطلوب وانسخ كل فتحات "الحبل" فيه بالتناوب مع memcpy نفسه.

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

في رأيي ، أنيقة جدا. :)

دعونا المعيار. كبيانات مصدر ، نأخذ الملف zend_vm_execute.h (IMHO سيكون هذا صحيحًا) لـ 71 ألف سطر وطباعته في 100 طريقة لـ 100 مرور ، مع إسقاط الحد الأدنى والحد الأقصى (بدأ كل قياس 10 مرات ، واختر الخيار الأكثر شيوعًا):

 <?php $file = explode("\n", file_get_contents("C:\projects\C\php-src\Zend\zend_vm_execute.h")); $out = []; for ($c = 0; $c < 100; $c++) { $start = microtime(true); ob_start(); $i = 0; foreach ($file as $line) { $i++; // echo 'line: ', $i, 'text: ', $line; // echo 'line: ' . $i . 'text: ' . $line; // echo "line: $i text: $line"; // printf('line: %d text: %s', $i, $line); } ob_end_clean(); $out[] = (microtime(true) - $start); } $min = min($out); $max = max($out); echo (array_sum($out) - $min - $max) / 98; 

ماذا نقيسمتوسط ​​الوقت بالثواني
"حبل"0.0129
عدة ECHO0.0135
سلسلة0.0158
printf ، للتأكد من اكتمالها0.0245

النتائج


  1. بالنسبة للسلاسل ذات الاستبدال البسيط ، تكون كل علامات الاقتباس المفاجئة والمثالية أكثر مثالية من علامات الاقتباس المفردة ذات السلاسل. وكلما طالت مدة استخدام الخطوط ، زاد الربح.
  2. الحجج مفصولة بفواصل ... هناك العديد من الفروق الدقيقة. عن طريق القياس ، يكون أسرع من التسلسل وأبطأ من "الحبل" ، ولكن هناك الكثير من "المتغيرات" المرتبطة بالإدخال / الإخراج.

استنتاج


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

بالنسبة لي شخصيا ، أنا لا أحب نهج التسلسل بسبب مظهر vyrviglazny ، على الرغم من أنه في بعض الحالات يمكن تبريره.

ملاحظة: إذا كان هذا النوع من التحليل مثيرًا للاهتمام - واسمحوا لي أن أعرف - فهناك الكثير الذي لا يزال بعيدًا عن الغموض والواضح دائمًا: مجموعة من الكائنات VS ، أو foreach VS بينما VS ، ، لديك الخيار ... :)

شرح قليلا من قراءة التعليقات


بناء جملة HEREDOC و "السلاسل المعقدة" (حيث تكون المتغيرات في أقواس داخلية) هي نفس السلاسل مزدوجة الاقتباس وتجميعها بنفس الطريقة تمامًا.

مزيج من PHP مع HTML مثل هذا:
 <?php $name = 'Vasya';?>Hello <?=$name?>! Have a nice day! 

هذا هو مجرد 3 صدى على التوالي.

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


All Articles