سؤال

تعد الوظائف المتداخلة في JavaScript مفيدة جدًا:الإغلاقات والأساليب الخاصة وماذا لديك..

ما هي وظائف PHP المتداخلة؟هل يستخدمها أحد ولماذا؟

إليكم تحقيقًا صغيرًا قمت به

<?php
function outer( $msg ) {
    function inner( $msg ) {
        echo 'inner: '.$msg.' ';
    }
    echo 'outer: '.$msg.' ';
    inner( $msg );
}

inner( 'test1' );  // Fatal error:  Call to undefined function inner()
outer( 'test2' );  // outer: test2 inner: test2
inner( 'test3' );  // inner: test3
outer( 'test4' );  // Fatal error:  Cannot redeclare inner()
هل كانت مفيدة؟

المحلول

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

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

والمثال "العالم الحقيقي" الوحيد الذي يمكن أن حفر هو href="http://www.java2s.com/Code/Php/Functions/Nestedfunction.htm" هذا التي يمكن تشغيلها مرة واحدة فقط، ويمكن إعادة كتابة نظافة IMO.

واستخدام الوحيد الذي يمكنني أن أفكر في لوحدات للدعوة الى [اسم] طريقة _include الذي يضع العديد من الطرق المتداخلة في الفضاء العالمي جنبا إلى جنب مع

if (!function_exists ('somefunc')) {
  function somefunc() { }
}

والشيكات.

وOOP PHP ستكون الواضح أن أفضل خيار:)

نصائح أخرى

إذا كنت تستخدم PHP 5.3 يمكنك الحصول على المزيد من السلوك Javacript مثل مع وظيفة غير معروفة:

<?php
function outer() {
    $inner=function() {
        echo "test\n";
    };

    $inner();
}

outer();
outer();

inner(); //PHP Fatal error:  Call to undefined function inner()
$inner(); //PHP Fatal error:  Function name must be a string
?>

وإخراج:

test
test

[إعادة كتابة وفقا لتصريحات ادلى بهاPierredeLESPINAY.]

وانها ليست مجرد أثر جانبي على الإطلاق، ولكن في الواقع ميزة مفيدة جدا لل<م> تعديل منطق البرنامج بشكل حيوي. انها من الأيام PHP الإجرائية، ولكن يمكن أن تأتي في متناول اليدين مع أبنية OO أيضا، إذا كنت ترغب في توفير تطبيقات بديلة عن وظائف معينة بذاتها في الطريق الأكثر مباشرة ممكن. (بينما OO هو الخيار الأفضل في معظم الوقت، فإنه خيار، وليس ولاية، وبعض مهام بسيطة لا تحتاج إلى العناصر غير المرغوب فيها اضافية.)

وعلى سبيل المثال، إذا كنت حيوي / مشروط تحميل الإضافات من الإطار الخاص بك، وتريد أن تجعل حياة الكتاب المساعد السوبر سهلة، يمكنك تقديم تطبيقات الافتراضية لبعض الوظائف الهامة إلا أن المساعد لا تتجاوز:

<?php // Some framework module

function provide_defaults()
{
    // Make sure a critical function exists:
    if (!function_exists("tedious_plugin_callback"))
    {
        function tedious_plugin_callback()
        {
        // Complex code no plugin author ever bothers to customize... ;)
        }
    }
}

وظائف محددة في وظائف لا استطيع ان ارى فائدة كبيرة لكنها الوظائف المحددة بشروط أستطيع. على سبيل المثال:

if ($language == 'en') {
  function cmp($a, $b) { /* sort by English word order */ }
} else if ($language == 'de') {
  function cmp($a, $b) { /* sort by German word order; yes it's different */ }
} // etc

وبعد ذلك كل يحتاج التعليمات البرمجية الخاصة بك القيام به هو استخدام وظيفة "CMP" في أشياء مثل usort () يدعو حتى لا يتحقق اللغة القمامة في جميع أنحاء التعليمات البرمجية. الآن أنا لم تفعل هذا ولكن أستطيع أن أرى الحجج لفعل ذلك.

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

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

وبصفة عامة، وذلك باستخدام جافا سكريبت كمعيار التي يمكن من خلالها تقييم لغات البرمجة الأخرى القائمة C هو فكرة سيئة. جافا سكريبت هو بالتأكيد الحيوانية الخاصة به بالمقارنة مع PHP، بيثون، بيرل، C، C ++، وجافا. بالطبع، هناك الكثير من أوجه الشبه العامة، ولكن نيتي وتفاصيل شجاع (المرجع <م> جافا سكريبت: الدليل النهائي، 6th الطبعة، الفصول 1-12 )، عندما إيلاء اهتمام ل، وجعل الأساسية جافا سكريبت فريدة من نوعها، جميلة، مختلفة وبسيطة ومعقدة في آن واحد. هذا هو بلدي اثنين سنتا.

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

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

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

في الدعوة خدمة ويب وجدنا أنه النفقات العامة أقل بكثير (الذاكرة والسرعة) بما في ذلك حيوي بطريقة متداخلة، وظائف الفردية على مكتبات كاملة من 1000s من وظائف. قد يكون مكدس الاستدعاءات نموذجي بين 5-10 المكالمات عميقة تتطلب سوى ربط عشرات الملفات 1-2kb كان ديناميكيا أفضل من بينهم ميغا بايت. وقد تم ذلك فقط من خلال خلق يتطلب صغير UTIL وظيفة التفاف. تصبح وظائف وشملت المتداخلة ضمن مهام فوق كومة المكالمة. نرى أنه على النقيض من فصول كاملة من 100s من الوظائف التي لم تكن مطلوبة على كل مكالمة خدمة ويب ولكن يمكن أن تستخدم أيضا ميزات تحميل كسول يحمل في ثناياه عوامل فب.

وأنا أعلم أن هذه هي وظيفة القديمة ولكن FWIW I استخدام وظائف متداخلة لإعطاء نهج نظيفة ومرتبة لدعوة متكررة عندما كنت فقط بحاجة إلى وظائف محليا - على سبيل المثال لبناء الأجسام الهرمية الخ (من الواضح أن عليك أن تكون حذرا وظيفة الأم ويطلق مرة واحدة فقط):

function main() {
    // Some code

    function addChildren ($parentVar) {
        // Do something
        if ($needsGrandChildren) addChildren ($childVar);
    }
    addChildren ($mainVar); // This call must be below nested func

    // Some more code
}

وهناك نقطة بالملاحظة في بي مقارنة مع JS على سبيل المثال هو أن استدعاء الدالة المتداخلة تحتاج إلى أن يتم بعد، أي أقل، وإعلان وظيفة (مقارنة مع JS حيث الدعوة وظيفة يمكن أن تكون في أي مكان ضمن الدالة الأم

إذا كنت تستخدم PHP 7، فراجع هذا:سيعطيك هذا التنفيذ فكرة واضحة عن الوظيفة المتداخلة.لنفترض أن لدينا ثلاث وظائف (أيضًا () وboo () وzoo ()) متداخلة في الوظيفة foo ().boo() وzoo() لهما نفس الوظيفة المتداخلة المسماة xoo().الآن في هذا الكود قمت بالتعليق على قواعد الوظائف المتداخلة بشكل واضح.

   function foo(){
        echo 'foo() is called'.'<br>';
        function too(){
            echo 'foo()->too() is called'.'<br>';
        }
        function boo(){
            echo 'foo()->boo() is called'.'<br>';
            function xoo(){
                echo 'foo()->boo()->xoo() is called'.'<br>';
            }
            function moo(){
                echo 'foo()->boo()->moo() is called'.'<br>';
            }
        }
        function zoo(){
            echo 'foo()->zoo() is called'.'<br>';
            function xoo(){     //same name as used in boo()->xoo();
                echo 'zoo()->xoo() is called'.'<br>';
            }
        #we can use same name for nested function more than once 
        #but we can not call more than one of the parent function
        }
    }

/****************************************************************
 * TO CALL A INNER FUNCTION YOU MUST CALL OUTER FUNCTIONS FIRST *
 ****************************************************************/
    #xoo();//error: as we have to declare foo() first as xoo() is nested in foo()

    function test1(){
        echo '<b>test1:</b><br>';
        foo(); //call foo()
        too();
        boo();
        too(); // we can can a function twice
        moo(); // moo() can be called as we have already called boo() and foo()
        xoo(); // xoo() can be called as we have already called boo() and foo()
        #zoo(); re-declaration error
        //we cannont call zoo() because we have already called boo() and both of them have same named nested function xoo()
    }

    function test2(){
        echo '<b>test2:</b><br>';
        foo(); //call foo()
        too();
        #moo(); 
        //we can not call moo() as the parent function boo() is not yet called
        zoo(); 
        xoo();
        #boo(); re-declaration error
        //we cannont call boo() because we have already called zoo() and both of them have same named nested function xoo()

    }

الآن إذا قمنا باستدعاء test1()‎ فسيكون الناتج كما يلي:

test1:
foo() is called
foo()->too() is called
foo()->boo() is called
foo()->too() is called
foo()->boo()->moo() is called
foo()->boo()->xoo() is called

إذا اتصلنا بـ test2()‎ فسيكون الناتج كما يلي:

test2:
foo() is called
foo()->too() is called
foo()->zoo() is called
zoo()->xoo() is called

لكن لا يمكننا استدعاء كل من text1() و test2() في نفس الوقت لتجنب خطأ إعادة التصريح

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

وظائف متداخلة مفيدة في التحفيظ (النتائج وظيفة التخزين المؤقت لتحسين الأداء).

<?php
function foo($arg1, $arg2) {
    $cacheKey = "foo($arg1, $arg2)";
    if (! getCachedValue($cacheKey)) {
        function _foo($arg1, $arg2) {
            // whatever
            return $result;
        }
        $result = _foo($arg1, $arg2);
        setCachedValue($cacheKey, $result);
    }
    return getCachedValue($cacheKey);
}
?>

وظائف متداخلة هي مفيدة إذا كنت تريد وظيفة المتداخلة للاستفادة من المتغير الذي أعلن في وظيفة الأم.

<?php
ParentFunc();
function ParentFunc()
{
  $var = 5;
  function NestedFunc()
  {
    global $var;
    $var = $var + 5;
    return $var;
  };
  echo NestedFunc()."<br>";
  echo NestedFunc()."<br>";
  echo NestedFunc()."<br>";
}
?>
scroll top