将匿名函数添加到类中的数组中


Add anonymous function to array in class

我是PHP的新手,但对JavaScript做了很多工作。我试着做以下事情:

class MyClass {
  private $someAnonymousFunction = function($any){
    return $any;
  };
  $data = [
    ['some String', $someAnonymousFunction]
  ];
}

但当我创建someAnonymousFunction时,它会出现一个错误,说它不喜欢我那样把functionunexpected 'function' (T_FUNCTION))放在那里。除了上面的例子,我已经尝试了不同的场景,但似乎同样的错误也会发生。

更新为什么要这样做。我想这样做是因为我想在创建类时抽象掉很多锅炉板。如果我要一遍又一遍地编写代码,我希望尽可能简单明了。以下是我的完整代码(请注意,这只是为了上课,我正在把它远远超出它需要的范围):

abstract class Protection {
    const Guard = 0;
    const Open = 1;
}
abstract class __ {
    public function identity($any) {
        return $any;
    }
}
// This is the core logic behind the class    
trait Property {
    public function get($name) {
        if ($this->data[$name][1] == Protection::Open) {
            return $this->data[$name][0];
        }
        else {
            //throw error
        }
    }
    public function set($name, $set) {
        if ($this->data[$name][1] == Protection::Open) {
            //Guard function can throw error or filter input
            $func = $this->data[$name][2];
            $this->data[$name][0] = $func($set);
            return $this;
        }
        else {
            // throw error
        }
    }
}
class Monster {
    use Property;
    //Just trying to get this to work. Throws error.
    private $identity = function($any) {
        return $any;
    };
    private $data = [
        'hairColor' => [
            'brown',
            Protection::Open,
            ucwords
        ],
        'killType' => [
            'sword',
            Protection::Open,
            __::identity  //Doesn't work either thinks it's a constant.
        ] 
    ];
}

$generic = new Monster();
echo '<br> Hair color: ' . $generic->get('hairColor') . ', Kill type: ' 
     . $generic->get('killType') . '<br>';
$generic->set('hairColor', 'blue')->set('killType', 'silver bullet');

更新2:这是"最终"代码:

<?php
class Utils {
    static function identity($any) {
        return $any;
    }
}
// Property abstracts much of the boiler plate away
// from making classes with getters and setters.
// It is chainable by default.
// It takes a variable named `data` which holds an
// associative array, with the keys being the names 
// of the properties/methods. The key holds a value
// which is an indexed array where:
// Index 0 == Value of property.
// [Index 1] == Optional string name of guard function.
// [Index 2] == Optional string name of method called 
//              with `get` method.
// It has two public methods:
// `get` returns value of property or calls a method.
// `set` gives a new value to a property.
trait Property {
    // Create a new property with attributes in an array.
    private function createNewProperty($name, $set) {
        $this->data[$name] = (is_array($set)) ? $set : [$set];
    }
    // Return property value
    public function get($name) {
        // If the property doesn't exist throw an error.
        if (!isset($this->data[$name])) {
            throw new Exception('No such property or method '.$name);
        }
        // copy by reference value into differently 
        // named variable to make code more concise.
        $prop =& $this->data[$name];
        // determine if property is a method.
        if (isset($prop[2]) && $prop[2]) {
            // call method with property value
            return call_user_func($prop[2], $prop[0]);
        }
        else {
            //return plain property value
            return $prop[0];
        }
    }
    // Set property value
    public function set($name, $set) {
        // If property isn't set then create one
        if (!isset($this->data[$name])) {
            createNewProperty($name, $set);
        }
        // copy by reference value into differently 
        // named variable to make code more concise.
        $prop =& $this->data[$name];
        // determine if guards exist when setting property
        if (isset($prop[1]) && $prop[1]) {
            $prop[0] = call_user_func($prop[1], $set);
            return $this; // make chainable
        }
        else {
            // set plain property
            $prop[0] = $set;
            return $this; // make chainable
        }
    }
}
class Monster {
    use Property;
    private $data = [
        'hairColor' => ['brown', ['Utils', 'identity']],
        'killType' => ['sword', 'ucwords'],
        'simple' => ['simple value', null, 'ucwords'],
    ];
}
$generic = new Monster();
echo '<br> Hair color: ' . $generic->get('hairColor') . ', Kill type: ' 
     . $generic->get('killType') . '<br>';
$generic->set('hairColor', 'blue')->set('killType', 'silver bullet');
echo '<br> Hair color: ' . $generic->get('hairColor') . ', Kill type: ' 
     . $generic->get('killType') . '<br>';
echo '<br>Simple: '.$generic->get('simple');
$generic->set('simple', 'simple value changed!');
echo '<br>Simple: '.$generic->get('simple');
?>

您不能在这样的属性声明中指定任意表达式,只能指定常数值,或者在最近对解析器进行更改时,指定某些常数值表达式。

然而,用初始值声明属性实际上只是声明属性然后在构造函数中初始化它的简写,因为无论何时创建新实例,都会进行初始赋值。

所以下面的两个类的行为是相同的:

class Foo1 {
     private $bar = 42;
}
class Foo2 {
     private $bar;
     public function __construct() {
            $this->bar = 42;
     }
 }

由于在构造函数中可以进行的赋值没有限制,这允许您将代码重写为如下(您在$data上缺少访问说明符,所以我假设private):

class MyClass {
      private $someAnonymousFunction;
      private $data;
      public function __construct() {
             $this->someAnonymousFunction = function($any){
                  return $any;
             };
             $this->data = [
                  ['some String', $this->someAnonymousFunction]
             ];
       }
}

只能使用编译时常数值初始化字段。我猜匿名函数不算常数值。