search

Home  >  Q&A  >  body text

php - 为什么这里的闭包函数无法调用?此外魔术方法也未被调用

我的代码是这样的:

<?php
class stdObject{
    public function  __construct(array $params=array()){
        if(!empty($params))
            foreach ($params as $key => $value) 
                $this->{$key}=$value;
    }

    public function __call($methodName,$params){
        $params=array_merge(array('stdObject'=>$this),$params);
        if(isset($this->{$methodName})&&is_callable($methodName)){
            //$params就是函数的参数,这里的stdObject就是function中的$stdObject;
            return call_user_func_array($methodName,$params);
        } else {
            throw new Exception("Fatal error: Call to undefined method stdObject::{$methodName}()");
        }
    }

}

echo  phpversion();
$obj = new stdObject();
$obj->name = "Nick";
$obj->surname = "Doe";
$obj->age = 20;
$obj->adresse = null;
$obj->getInfo = function($stdObject) { 
    // $stdObject referred to this object (stdObject).
    echo $stdObject->name . " " . $stdObject->surname . " have " . $stdObject->age . " yrs old. And live in " . $stdObject->adresse;
};

print_r($obj);
$obj->getInfo();
?>

首先,按道理说,调用一个类中间不存在的成员变量,因该显示的的调用魔术方法_set,但是这里没有显示的声明_set方法;
2.为什么我无法调用$obj->getInfo()方法呢?一旦调用就会抛出异常
'Fatal error: Call to undefined method stdObject::getInfo(),就说明这个方法不存在

怪我咯怪我咯2821 days ago532

reply all(2)I'll reply

  • PHPz

    PHPz2017-04-10 14:54:59

    首先,缩进是谁弄的,快站出来,我保证不打死你哦…另外回答你的问题:

    1. 你都知道调用不可访问的成员变量时会调用魔术方法__set(),那你为啥不定义呢!你不定义你怎么让人家工作嘛,就好像你不给工作内容给我但是你希望我每天干的跟狗一样?别逗好么!请自行增加魔术方法定义好么!

      
      class stdObject {
          private function __set($name, $value) {
              $this->$name = $value;
          }
      }
      

    2. PHP中成员属性和成员函数的定义方法是不一样的,我还没见过用$this->method = function() {}这样定义成员函数的,你这是把JavaScript的思想代入到PHP中来了吧。所以在调用不可访问成员函数的时触发__call()魔术方法中,你的isset()判断是真,但是is_callable()会返回假(对了这里还要提醒一个笔误,是is_callable($this->$methodName)不是is_callable($methodName),两个完全不一样好么!你以为你把变量名字叫做methodName你不给$this程序就会自动的给你调用成员函数么!坑爹呢!!),然后你的语法会抛出一个异常出来。

    reply
    0
  • PHP中文网

    PHP中文网2017-04-10 14:54:59

    公子哥您在逗我。我将is_callable($methodName)变成is_callable($this->{$methodName})成功运行了。我的原因是错在这里。而不是魔术方法。而且达到了我想要的效果。现在代码是这样的:

    <?php
    
    class stdObject{
    
    
    
        public  function  __construct(array $params=array()){
    
            if(!empty($params)){
       foreach ($params as $key => $value) {
    
        $this->{$key}=$value;
        
       }
    
                
            }
        }
    
        public function __call($methodName,$params){
    
          $params=array_merge(array('stdObject'=>$this),$params);
          if(isset($this->{$methodName})&&is_callable($this->{$methodName})){
            //$params就是函数的参数,这里的stdObject就是function中的$stdObject;
            return call_user_func_array($this->{$methodName},$params);
          }
       else{
        throw new Exception("Fatal error: Call to undefined method stdObject::{$methodName}()");
     
        }
        }
    
    };
    
    $obj = new stdObject();
    $obj->name = "Nick";
    $obj->surname = "Doe";
    $obj->age = 20;
    $obj->adresse = null;
    $obj->getInfo = function($stdObject) { // $stdObject referred to this object (stdObject).
        echo $stdObject->name . " " . $stdObject->surname . " have " . $stdObject->age . " yrs old. And live in " . $stdObject->adresse;
    };
    
    $obj->getInfo();
    ?>
    
    

    运行的结果是:
    Nick Doe have 20 yrs old. And live in
    首先,我想说的是,公子哥的基础不太扎实。$this->method = function() {}当然可以这样定义成员函数。此外,调用一个不存在的属性,不一定要显示的指定_set方法。
    ---------------------------------------------------------------------------------------------------------------知道我为啥会这样做吗?因为php官方手册就是这样写的:
    [#1] Ashley Dambra [2014-02-21 06:50:10]
    Here a simple class 'stdObject' that give us the possibility to create dynamic classes and the possibility to add and execute methods thing that 'stdClass' don't let us do. Very useful if you extends it to a controller on MVC Design pattern. Let users create own classes.
    I have also post this class on http://www.php.net/manual/en/language.types.object.php

    <?php
    class stdObject {
        public function __construct(array $arguments = array()) {
            if (!empty($arguments)) {
                foreach ($arguments as $property => $argument) {
                    $this->{$property} = $argument;
                }
            }
        }
    
        public function __call($method, $arguments) {
            $arguments = array_merge(array("stdObject" => $this), $arguments); // Note: method argument 0 will always referred to the main class ($this).
            if (isset($this->{$method}) && is_callable($this->{$method})) {
                return call_user_func_array($this->{$method}, $arguments);
            } else {
                throw new Exception("Fatal error: Call to undefined method stdObject::{$method}()");
            }
        }
    }
    
    // Usage.
    
    $obj = new stdObject();
    $obj->name = "Nick";
    $obj->surname = "Doe";
    $obj->age = 20;
    $obj->adresse = null;
    
    $obj->getInfo = function($stdObject) { // $stdObject referred to this object (stdObject).
        echo $stdObject->name . " " . $stdObject->surname . " have " . $stdObject->age . " yrs old. And live in " . $stdObject->adresse;
    };
    
    $func = "setAge";
    $obj->{$func} = function($stdObject, $age) { // $age is the first parameter passed when calling this method.
        $stdObject->age = $age;
    };
    
    $obj->setAge(24); // Parameter value 24 is passing to the $age argument in method 'setAge()'.
    
    // Create dynamic method. Here i'm generating getter and setter dynimically
    // Beware: Method name are case sensitive.
    foreach ($obj as $func_name => $value) {
        if (!$value instanceOf Closure) {
    
            $obj->{"set" . ucfirst($func_name)} = function($stdObject, $value) use ($func_name) {  // Note: you can also use keyword 'use' to bind parent variables.
                $stdObject->{$func_name} = $value;
            };
    
            $obj->{"get" . ucfirst($func_name)} = function($stdObject) use ($func_name) {  // Note: you can also use keyword 'use' to bind parent variables.
                return $stdObject->{$func_name};
            };
    
        }
    }
    
    $obj->setName("John");
    $obj->setAdresse("Boston");
    
    $obj->getInfo();
    ?> 
    

    reply
    0
  • Cancelreply