هل من الممكن الإفراط في استخدام الربط الثابت المتأخر في PHP؟

StackOverflow https://stackoverflow.com/questions/1816560

سؤال

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

خذ بعين الاعتبار هذه الأمثلة:

1.منشئي الراحة (::create())

class SimpleObject
{
    public function __construct() { /* ... */ }

    public static function create()
    {
        return new static; // or: return new self;
    }
}

إذا كان من الممكن توسيع هذه الفئة (ومع ذلك، لم يتم توسيعها بواسطة أي فئة في نفس الحزمة)، فهل يجب استخدام الربط الثابت المتأخر فقط لتسهيل توسيعها (دون الحاجة إلى إعادة كتابة ::create() الطريقة، والأهم من ذلك، دون الحاجة إلى تذكر القيام بذلك)؟

ملحوظة:يتم استخدام هذا المصطلح للتغلب على استحالة استدعاء الأساليب على الكائنات التي تم إنشاؤها للتو: new SimpleObject()->doStuff() غير صالح في PHP.


2.ثوابت الطبقة

class TagMatcher
{
    const TAG_PATTERN = '/\<([a-z\-]+?)\>/i';

    private $subject;

    public function construct($subject) { $this->subject = $subject; }

    public function getAllTags()
    {
        $pattern = static::TAG_PATTERN;
        preg_match_all($pattern, $this->subject);
        return $pattern[1];
    }
}

سبب الاستخدام static:: في هذا المثال مشابه للمثال السابق.يتم استخدامه فقط لأنه يمكن جعل هذه الفئة لمطابقة العلامات ذات الأشكال المختلفة فقط عن طريق توسيعها وتجاوز الثابت.


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

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

المحلول

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

يؤدي إدخال الارتباط الثابت المتأخر إلى إصلاح خلل في نموذج كائن PHP.لا يتعلق الأمر بالأداء، بل يتعلق بالدلالات.

على سبيل المثال، أحب استخدام الأساليب الثابتة عندما لا يتم استخدام تنفيذ الطريقة $this.فقط لأن الطريقة ثابتة لا يعني أنك لا تريد تجاوزها في بعض الأحيان.قبل PHP 5.3، كان السلوك هو أنه لم يتم وضع علامة على أي خطأ إذا قمت بتجاوز طريقة ثابتة، ولكن PHP ستمضي قدمًا وتستخدم الإصدار الأصلي بصمت.على سبيل المثال، الكود أدناه يطبع "A" قبل PHP 5.3.هذا سلوك غير متوقع للغاية.

يعمل الربط الثابت المتأخر على إصلاح المشكلة، والآن يطبع نفس الرمز "B".

<?php
class A {
  public static function who() {
    echo __CLASS__;
  }
  public static function test() {
    static::who();
  }
}

class B extends A {
  public static function who() {
    echo __CLASS__;
  }
}

B::test();
?>

نصائح أخرى

تؤدي الطرق الثابتة (المرتبطة مبكرًا أو متأخرًا) إلى إنشاء اقتران محكم و(وبالتالي) تقليل قابلية الاختبار.يمكنك إنشاء برامج كبيرة بلغة PHP دون استخدام أكثر من عدد قليل من الاستدعاءات الثابتة.بالنسبة لي، الأساليب الثابتة المتأخرة ليست ميزة.

يحرر للإجابة على سؤال ماركو ديمايو، كيف تقلل الطريقة الثابتة من قابلية الاختبار؟

أنا آسف إذا كان هذا واضحًا لك أيها الأعضاء الثابتون (البيانات والأساليب) نكون مفيدة ولا تضر إذا استخدمت بمسؤولية، كنت أشير إلى سوء استخدامها السائد.

لنفترض أن لديك تطبيق ويب يستخدم قاعدة بيانات SQL.قد تقوم كائنات عملك باسترداد البيانات باستخدام واجهة ثابتة أو من خلال تعدد الأشكال.أيضاً

class MyBusinessObject
extends...
{
  public function doThisOrThat(...)
  {
    $results = db::query('sql string...');
    ...
  }
}

أو

class MyBusinessObject
extends...
{
  public function __construct(dbconn $db)
  {
    $this->db = $db;
  }
  private $db;
  public function doThisOrThat(...)
  {
    $results = $this->db->query('sql string...');
    ...
  }
}

هذا الأخير أسهل في الاختبار (كما في:أريد اختبار أن سلسلة SQL التي تم إنشاؤها من مدخلات كذا وكذا هي كذا وكذا) لأنه من الأسهل إنشاء تطبيق آخر لـ dbconn واجهة مما هو عليه لتغيير معنى db::.لماذا تريد سواء؟لأنك لا تحتاج إلى قاعدة بيانات حقيقية لاختبار سلوك إنشاء SQL، وفي الواقع من الأسهل اختبارها بدون قاعدة بيانات حقيقية.أيضًا، من الأسهل استبعاد مستهلك SQL إذا كانت اختباراتك معنية بجانب آخر من CUT (الكود قيد الاختبار).

يتضمن الاختبار دائمًا الكذب على الكود الذي تم اختباره بشأن المتعاونين معه، والامتناع عن الواجهات الثابتة ("القولون المزدوج" أو "الرباعي") يعني أن الكذب ليس من الضروري أن يكون عملية جراحية ضخمة، وهو ما يعد ميزة إضافية، نظرًا لأنه كلما ابتعد الكود الذي تم اختباره عن رمز الإنتاج، كلما كانت نتائج الاختبار أقل أهمية.

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

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

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top