【问题标题】:php callback (like jQuery)?php回调(如jQuery)?
【发布时间】:2011-07-17 18:49:19
【问题描述】:

在 jQuery 中你可以写类似的东西


$(selector).bind('click', function(e) {
      // something was true - do these actions.
});


我想知道在 php 中你是否可以在不使用 eval 的情况下做类似的事情。

像这样?我知道这行不通。


class act{
    public function bind($pref, $callback) {

       if($pref == 'something' ) {
             // return and perform actions in $callback?
             eval($callback);
       }
    }
}

有些人可能会问,这样做有什么需要?好吧,我正在尝试在不使用太多 if 语句的情况下简化我的代码。


$act = new act;

$act->bind('something', function(e) {
      echo 'this was the php code to run in the callback';
});

上面的代码可以避免使用一堆 if 语句。


$act = new act;

if( $act->bind('something') ) {
      // bind returned true so do this?
}

我知道你可以使用 ob_get_contents 来返回经过评估的代码,但是 ewww。


ob_start();
eval('?> ' . $callback . '<?php ');
$evaled = ob_get_contents();
ob_end_clean();

return $evaled;

【问题讨论】:

  • 检查我在答案中发布的示例,它完全符合您的要求

标签: php callback return


【解决方案1】:

你确实可以在PHP中定义回调函数(或方法)

这可以通过以下任一方式实现:


对于几个示例,请查看以下手册页的 callback 部分:Pseudo-types and variables used in this documentation

【讨论】:

    【解决方案2】:
    if($pref == 'something' ) {
            // return and perform actions in $callback?
            call_user_func($callback);
    }
    

    call_user_func 做你想做的事,你甚至可以传递参数

    http://it.php.net/call_user_func

    示例

    function g($msg,$func){
        echo $msg;
    
        call_user_func($func);
    }
    
    g('hello',function (){echo 'hello2';});
    
    // prints: hellohello2
    

    【讨论】:

    • 从安全角度来说,这不是一个有风险的解决方案吗?
    • @kr1zmo: 是的,但考虑到 call_user_func 从 php 4 开始可用
    • 如果你看到我的代码,我做了它以便它与 PHP 4+ 兼容,但也使用匿名函数。这可以在我的类的两个帮助器/实用程序(受保护的静态)方法中看到。
    【解决方案3】:

    如果您要向回调传递多个参数,请使用call_user_func_array,类似于已经提到的call_user_func,除了作为第二个参数,它需要一个参数数组。

    $functionName = 'foo';
    $functionArgs = array('bar', 'baz');
    call_user_func_array($functionName, $functionArgs);
    

    或者,您可以传递匿名函数,而不是函数名。

    $functionBody = function($arg1, $arg2){
            echo $arg1 . $arg2;
        };
    $functionArgs = array('bar', 'baz');
    call_user_func_array($functionBody, $functionArgs);
    

    匿名函数可以像本例一样作为变量传递,也可以直接内联声明为参数。

    【讨论】:

      【解决方案4】:

      PHP 5.3 实际上添加了匿名函数,因此您基本上可以将一个函数作为参数传递给另一个函数调用并从那里执行它。

      http://php.net/manual/en/functions.anonymous.php

      $callback = function($name){
          printf("Hello %s\r\n", $name);
      };
      
      $act->bind('test', $callback);
      

      【讨论】:

        【解决方案5】:

        到目前为止,其他答案都很棒,但是鉴于您的主要兴趣是事件,我将向您展示如何做到这一点,以及链接(奖励!)。

        /**
         * jQuery events+chaining prototype.
         */
        class pQuery {
        
            /// PROTECTED PROPERTIES ///
        
            /**
             * @var array Holds list of event=>callbacks items.
             */
            protected $events=array();
        
            /// PROTECTED UTILITY METHODS ///
        
            /**
             * Creates an anonymous function compatible with PHP 4+.
             * <b>IMPORTANT</b> It is likely functions made this way are not garbage collected.
             * @param $funcCode string Function decleration, including the body.
             * @return string The newly created function's name.
             */
            protected static function mk_anonFunc($funcCode){
                static $counter=0;
                $func='pQanon'.(++$counter);
                @eval('function '.$func.'('.substr($funcCode,9));
                if(!function_exists($func))
                    die('Fatal: Anonymous function creation failed!');
                return $func;
            }
        
            /**
             * Detects whether a string contains an anonymous function or not.
             * @param $funcCode string Function decleration, including the body.
             * @return boolean True if it does contain an anonymous function, false otherwise.
             */
            protected static function is_anonFunc($funcCode){
                return strpos($funcCode,'function(')!==false;
            }
        
            /// PUBLIC METHODS ///
        
            /**
             * Bind event callback to this jQuery instance.
             * @param string $event The event name, eg: 'click'.
             * @param string|array $callback A function or a class/instance method, eg: 
             *        'myFunc' OR array('myClass','myMtd') OR array($obj,'myMtd'). 
             * @return pQuery Chaining.
             */
            public function bind($event,$callback){
                if(self::is_anonFunc($callback))
                    $callback=self::mk_anonFunc($callback);
                if(!isset($this->events[$event]))
                    $this->events[$event]=array();
                $this->events[$event][]=$callback;
                return $this;
            }
            /**
             * Unbind event callback from this jQuery instance.
             * @param string $event The event name, eg: 'click'.
             * @param string|array $callback A function or a class/instance method, eg: 
             *        'myFunc' OR array('myClass','myMtd') OR array($obj,'myMtd'). 
             * @return pQuery Chaining.
             */
            public function unbind($event,$callback){
                if(!isset($this->events[$event])){
                    if(($pos=array_search($callback,$this->events[$event]))!==false)
                        unset($this->events[$event][$pos]);
                }
                return $this;
            }
            /**
             * Trigger event, calling all related callbacks.
             * @param string $event The event name to trigger, eg: 'click'.
             * @param array $params Optional array of arguments to pass to callback.
             * @return pQuery Chaining.
             */
            public function trigger($event,$params=array()){
                if(isset($this->events[$event]))
                    foreach($this->events[$event] as $callback)
                        call_user_func_array($callback,$params);
                return $this;
            }
        }
        
        /**
         * Allows us to use factory-singleton pattern.
         * @return pQuery The $pQuery instance.
         */
        function pQuery(){
            global $pQuery;
            if(!isset($pQuery))
                $pQuery=new pQuery();
            return $pQuery;
        }
        

        这里有一个例子:

        // instantiate pQuery
        // Note: to use it like jQuery does, do it as follows
        // and then simply use "global $pQuery;" wherever you want it.
        $pQuery = new pQuery();
        
        // declare some sample callbacks
        function start(){ echo 'start'; }
        function stop(){ echo 'stop'; }
        
        // bind some stuff and call start
        $pQuery->bind('start','start')
               ->bind('stop','stop')
               ->trigger('start');
        
        // bind more stuff and call click
        $pQuery->bind('click','function(){ echo "clicked"; }')
               ->bind('custom','function(){ echo "custom"; }')
               ->bind('click','function(){ echo "clicked2"; }')
               ->trigger('click',array($pQuery,'arg2','arg3'));
        
        // call end
        $pQuery->trigger('stop');
        

        【讨论】:

        • 非常令人印象深刻的 Sciberras 先生
        • 欢迎您!希望您和我在使用它时一样享受它。顺便说一句,这是 K2F PHP 框架中的标准事件机制(以及具有类似架构的其他东西):github.com/uuf6429/K2F
        • 有没有办法在 $pQuery->bind('click', $act->run('1')); 中传递类似的东西;
        • kr1zmo - 即使在 jQuery 上下文中,这也没有意义,因为 $act-&gt;run(1) 会直接执行。相反,如果您的意思是:jQuery.bind('click',function(){ act-&gt;run(1) });,您也可以通过将其包装在 PHP 中来做到这一点,例如:$pQuery-&gt;bind('click', 'function(){ $act-&gt;run('1'); }');, 但是 这不能直接与我上面的代码一起使用,您需要使函数bind 检查 $callback 是否以"function(){" 开头,如果是,则正确解析它。如果你真的需要这个,我可以写在上面,问吧。
        • 好吧,我想我自己有点困惑我想要做的不是一遍又一遍地在彼此之间编写嵌套的 if 语句我想找到一种更简单的方法,也许是回调问题我问的不适合我的情况。回到正题,我想从一个类中调用公共函数,该函数返回一个值,然后我用该值做一些事情。目前,我只是在相互编写 if 语句,例如 if($act->isvalid = 0) { if($act->check() = 1) {// do this} }else { //do this}。知道其他方式不是一遍又一遍的陈述。
        猜你喜欢
        • 2016-01-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-01-25
        • 2011-09-29
        • 1970-01-01
        相关资源
        最近更新 更多