عمليات الإغلاق في PHP... ما هي على وجه التحديد ومتى ستحتاج إلى استخدامها؟

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

  •  02-07-2019
  •  | 
  •  

سؤال

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

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

المحلول

سيدعم PHP عمليات الإغلاق أصلاً في الإصدار 5.3.يعد الإغلاق أمرًا جيدًا عندما تريد وظيفة محلية تُستخدم فقط لبعض الأغراض الصغيرة والمحددة.ال RFC للإغلاق أعط مثالا جيدا:

function replace_spaces ($text) {
    $replacement = function ($matches) {
        return str_replace ($matches[1], ' ', ' ').' ';
    };
    return preg_replace_callback ('/( +) /', $replacement, $text);
}

يتيح لك هذا تحديد replacement وظيفة محليا في الداخل replace_spaces(), ، بحيث لا يكون:
1) تشوش مساحة الاسم العالمية
2) جعل الناس يتساءلون بعد ثلاث سنوات عن سبب وجود وظيفة محددة عالميًا يتم استخدامها فقط داخل وظيفة واحدة أخرى

إنها تحافظ على تنظيم الأشياء.لاحظ كيف أن الدالة نفسها ليس لها اسم، بل يتم تعريفها وتعيينها كمرجع لها $replacement.

لكن تذكر أنه عليك انتظار PHP 5.3 :)

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

// Set a multiplier  
 $multiplier = 3;

// Create a list of numbers  
 $numbers = array(1,2,3,4);

// Use array_walk to iterate  
 // through the list and multiply  
 array_walk($numbers, function($number) use($multiplier){  
 echo $number * $multiplier;  
 }); 

ويرد هنا شرح ممتاز ما هي php lambdas وعمليات الإغلاق

نصائح أخرى

عندما تحتاج في المستقبل إلى وظيفة تؤدي مهمة قررتها الآن.

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

يمكن إنشاء الإغلاق في (على سبيل المثال) config_parser();يقوم بإنشاء وظيفة تسمى do_hash_method() باستخدام المتغيرات المحلية ل config_parser() (من ملف التكوين).حينما do_hash_method() يسمى، لديه حق الوصول إلى المتغيرات في النطاق المحلي لconfig_parser() على الرغم من أنه لا يتم استدعاؤه في هذا النطاق.

مثال افتراضي جيد نأمل:

function config_parser()
{
    // Do some code here
    // $hash_method is in config_parser() local scope
    $hash_method = 'multiply';

    if ($hashing_enabled)
    {
        function do_hash_method($var)
        {
            // $hash_method is from the parent's local scope
            if ($hash_method == 'multiply')
                return $var * $var;
            else
                return $var ^ $var;
        }
    }
}


function hashme($val)
{
    // do_hash_method still knows about $hash_method
    // even though it's not in the local scope anymore
    $val = do_hash_method($val)
}

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

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

أنا أحب السياق الذي يقدمه منشور troelskn.عندما أريد أن أفعل شيئًا مثل مثال Dan Udey في PHP، أستخدم نمط إستراتيجية OO.في رأيي، هذا أفضل بكثير من تقديم وظيفة عالمية جديدة يتم تحديد سلوكها في وقت التشغيل.

http://en.wikipedia.org/wiki/Strategy_pattern

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

class ConfigurableEncoder{
        private $algorithm = 'multiply';  //default is multiply

        public function encode($x){
                return call_user_func(array($this,$this->algorithm),$x);
        }

        public function multiply($x){
                return $x * 5;
        }

        public function add($x){
                return $x + 5;
        }

        public function setAlgorithm($algName){
                switch(strtolower($algName)){
                        case 'add':
                                $this->algorithm = 'add';
                                break;
                        case 'multiply':        //fall through
                        default:                //default is multiply
                                $this->algorithm = 'multiply';
                                break;
                }
        }
}

$raw = 5;
$encoder = new ConfigurableEncoder();                           // set to multiply
echo "raw: $raw\n";                                             // 5
echo "multiply: " . $encoder->encode($raw) . "\n";              // 25
$encoder->setAlgorithm('add');
echo "add: " . $encoder->encode($raw) . "\n";                   // 10

بالطبع، إذا كنت تريد أن تكون متاحة في كل مكان، يمكنك فقط جعل كل شيء ثابتًا ...

الإغلاق هو في الأساس وظيفة تكتب لها التعريف في سياق واحد ولكن يتم تشغيله في سياق آخر.لقد ساعدتني Javascript كثيرًا في فهم هذه الأمور، لأنها تُستخدم في JavaScript في كل مكان.

في PHP، تكون أقل فعالية من JavaScript، وذلك بسبب الاختلافات في النطاق وإمكانية الوصول إلى المتغيرات "العالمية" (أو "الخارجية") من داخل الوظائف.ومع ذلك، بدءًا من PHP 5.4، يمكن لعمليات الإغلاق الوصول إلى الكائن $this عند تشغيلها داخل كائن، وهذا يجعلها أكثر فعالية.

هذا هو ما تدور حوله عمليات الإغلاق، وينبغي أن يكون كافيا لفهم ما هو مكتوب أعلاه.

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

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

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

 <?php
      $param='ironman';
      function sayhello(){
          $param='captain';
          $func=function () use ($param){
                $param='spiderman';
          };
       $func();
       echo  $param;
       }
      sayhello();
?>

//output captain

//and if we pass variable as a reference as(&$param) then output would be spider man;

فيما يلي أمثلة لعمليات الإغلاق في php

// Author: HishamDalal@gamil.com
// Publish on: 2017-08-28

class users
{
    private $users = null;
    private $i = 5;

    function __construct(){
        // Get users from database
        $this->users = array('a', 'b', 'c', 'd', 'e', 'f');
    }

    function displayUsers($callback){
        for($n=0; $n<=$this->i; $n++){
            echo  $callback($this->users[$n], $n);
        }
    }

    function showUsers($callback){
        return $callback($this->users);

    }

    function getUserByID($id, $callback){
        $user = isset($this->users[$id]) ? $this->users[$id] : null;
        return $callback($user);
    }

}

$u = new users();

$u->displayUsers(function($username, $userID){
    echo "$userID -> $username<br>";
});

$u->showUsers(function($users){
    foreach($users as $user){
        echo strtoupper($user).' ';
    }

});

$x = $u->getUserByID(2, function($user){

    return "<h1>$user</h1>";
});

echo ($x);

انتاج:

0 -> a
1 -> b
2 -> c
3 -> d
4 -> e
5 -> f

A B C D E F 

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