operation php




define() مقابل const (7)

سؤال واضح جدا: في PHP ، متى تستخدم

define('FOO', 1);

ومتى تستخدم

const FOO = 1;

ما هي الاختلافات الرئيسية بين هذين؟


أعتقد أنه اعتبارًا من PHP 5.3 ، يمكنك استخدام const خارج الصفوف ، كما هو موضح هنا في المثال الثاني:

http://www.php.net/manual/en/language.constants.syntax.php

<?php
// Works as of PHP 5.3.0
const CONSTANT = 'Hello World';

echo CONSTANT;
?>

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

اعتبارا من PHP 5.3 ، تتشابه الثوابت و المحددات في معظم النواحي. ومع ذلك ، لا تزال هناك بعض الاختلافات المهمة:

  • لا يمكن تعريف Consts من تعبير. const FOO = 4 * 3; لا يعمل ، ولكن define('CONST', 4 * 3); هل.
  • يجب أن يتضمن الاسم الذي تم تمريره define مساحة الاسم المراد تعريفها داخل مساحة الاسم هذه.

يجب أن يوضح الرمز أدناه الاختلافات.

namespace foo 
{
    const BAR = 1;
    define('BAZ', 2);
    define(__NAMESPACE__ . '\\BAZ', 3);
}

namespace {
    var_dump(get_defined_constants(true));
}

سيكون محتوى الصفيف الثانوي للمستخدم هو ['foo\\BAR' => 1, 'BAZ' => 2, 'foo\\BAZ' => 3] .

=== تحديث ===

سيتيح برنامج PHP 5.6 المرتقب المزيد من المرونة مع const . ستتمكن الآن من تحديد الثوابت من حيث التعبيرات ، شريطة أن تكون تلك التعبيرات مكونة من ثوابت أو حرفيات أخرى. هذا يعني أن ما يلي يجب أن يكون صالحًا اعتبارًا من 5.6:

const FOOBAR = 'foo ' . 'bar';
const FORTY_TWO = 6 * 9; // For future editors: THIS IS DELIBERATE! Read the answer comments below for more details
const ULTIMATE_ANSWER = 'The ultimate answer to life, the universe and everything is ' . FORTY_TWO;

لا تزال غير قادر على تعريف الثوابت من حيث المتغيرات أو إرجاع الدالة بالرغم من ذلك

const RND = mt_rand();
const CONSTVAR = $var;

سوف لا يزال خارج.


بدءًا من PHP 5.3 ، هناك طريقتان لتحديد الثوابت : إما باستخدام الكلمة الأساسية const أو استخدام الوظيفة define() :

const FOO = 'BAR';
define('FOO', 'BAR');

الاختلاف الأساسي بين هذين الطريقتين هو أن const يحدد الثوابت في وقت التحويل البرمجي ، بينما يحدد define في وقت التشغيل. هذا يسبب معظم عيوب const . بعض عيوب const هي:

  • لا يمكن استخدام const لتحديد الثوابت بشكل شرطي. لتحديد ثابت عالمي ، يجب استخدامه في النطاق الخارجي:

    if (...) {
        const FOO = 'BAR';    // invalid
    }
    // but
    if (...) {
        define('FOO', 'BAR'); // valid
    }
    

    لماذا تريد أن تفعل ذلك على أي حال؟ أحد التطبيقات الشائعة هو التحقق مما إذا كان الثابت محددًا بالفعل:

    if (!defined('FOO')) {
        define('FOO', 'BAR');
    }
    
  • يقبل const ثابت قياسي (رقم أو سلسلة أو ثابت آخر مثل true أو false أو null أو __FILE__ ) ، بينما يأخذ define() أي تعبير. بما أنه مسموح باستخدام تعبيرات ثابتة لـ PHP 5.6 في const :

    const BIT_5 = 1 << 5;    // valid since PHP 5.6, invalid previously
    define('BIT_5', 1 << 5); // always valid
    
  • يأخذ const اسم ثابت عادي ، بينما define() يقبل أي تعبير كاسم. هذا يسمح بفعل أشياء مثل هذه:

    for ($i = 0; $i < 32; ++$i) {
        define('BIT_' . $i, 1 << $i);
    }
    
  • const s دائمًا حساسة لحالة الأحرف ، بينما يتيح لك define() تحديد الثوابت غير الحساسة لحالة الأحرف عن طريق تمرير true كالوسيطة الثالثة:

    define('FOO', 'BAR', true);
    echo FOO; // BAR
    echo foo; // BAR
    

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

  • يقرأ ببساطة const ألطف. انها بناء اللغة بدلا من وظيفة وأيضا متسقة مع كيفية تعريف الثوابت في الطبقات.
  • يحدد const ثابت في مساحة الاسم الحالية بينما يجب أن يتم تمرير define() اسم مساحة الاسم الكامل:

    namespace A\B\C;
    // To define the constant A\B\C\FOO:
    const FOO = 'BAR';
    define('A\B\C\FOO', 'BAR');
    
  • نظرًا لأن const 5.6 لـ PHP يمكن أيضًا أن تكون صفائف ، بينما لا يدعم define() المصفوفات بعد. ومع ذلك ، سيتم دعم المصفوفات لكلتا الحالتين في PHP 7.

    const FOO = [1, 2, 3];    // valid in PHP 5.6
    define('FOO', [1, 2, 3]); // invalid in PHP 5.6, valid in PHP 7.0
    
  • بما أن const s هي بنى اللغة ومعرّفة في وقت الترجمة فهي أسرع قليلاً من define() s.

    من المعروف أن PHP define() s تكون بطيئة عند استخدام عدد كبير من الثوابت. حتى أن الناس قاموا باختراع أشياء مثل apc_load_constants() و hidef للتغلب على هذا.

    تجعل const تجعل تعريف الثوابت أسرع مرتين تقريبًا (على أجهزة التطوير مع XDebug قيد التشغيل أكثر). لا يتغير وقت البحث من ناحية أخرى (حيث أن كلا النوعين الثابتين يشتركان في نفس جدول البحث): Demo .

أخيرًا ، لاحظ أنه يمكن استخدام const أيضًا داخل فئة أو واجهة لتعريف ثابت صف ثابت أو واجهة ثابتة. define لا يمكن استخدامه لهذا الغرض:

class Foo {
    const BAR = 2; // valid
}
// but
class Baz {
    define('QUX', 2); // invalid
}

ملخص

ما لم تكن بحاجة إلى أي نوع من التعريف الشرطي أو التعبيري ، استخدم const بدلاً من define() s - ببساطة من أجل قابلية القراءة!


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

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

مثال على استخدام const جيد هو التخلص من الأرقام السحرية. نلقي نظرة على ثوابت الشركة . عندما تحتاج إلى تحديد نوع الجلب ، يمكنك كتابة PDO::FETCH_ASSOC ، على سبيل المثال. إذا لم يتم استخدام الثوابت ، فستنتهي بكتابة شيء مثل 35 (أو ما يتم تعريفه بـ FETCH_ASSOC ). هذا لا معنى له للقارئ.

مثال على define الاستخدام الجيد ربما يحدد المسار الجذر للتطبيق الخاص بك أو رقم إصدار المكتبة.


لا أحد يقول شيئًا عن php-doc ، لكن بالنسبة لي هذه أيضًا حجة مهمة جدًا لتفضيل const :

/**
 * My foo-bar const
 * @var string
 */
const FOO = 'BAR';

معظم هذه الإجابات خاطئة أو لا تخبرنا إلا بنصف القصة.

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

فمثلا:

const AWESOME = 'Bob'; // Valid

مثالا سيئا:

const AWESOME = whatIsMyName(); // Invalid (Function call)
const WEAKNESS = 4+5+6; // Invalid (Arithmetic) 
const FOO = BAR . OF . SOAP; // Invalid (Concatenation)

لإنشاء ثوابت متغير استخدم تعريف () مثل:

define('AWESOME', whatIsMyName()); // Valid
define('WEAKNESS', 4 + 5 + 6); // Valid
define('FOO', BAR . OF . SOAP); // Valid

define استخدام الثوابت العالمية.

const أنا استخدم للثوابت الطبقية.

لا يمكنك define نطاق الفئة ، const يمكنك. وغني عن القول ، لا يمكنك استخدام const خارج نطاق الفئة

أيضا ، مع const ، يصبح في الواقع عضوا في الصف ، مع define ، سيتم دفعه إلى النطاق العالمي.





constants