在类中向数组添加匿名函数

时间:2014-10-15 00:41:58

标签: php anonymous-function

我是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 :这是&#34; final&#34;代码:

<?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');

?>

2 个答案:

答案 0 :(得分:1)

您不能在类似的属性声明中分配任意表达式,只能使用常量值,或者对解析器的最近更改,某些常量值表达式。

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

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

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

由于您可以在构造函数中对赋值进行限制,因此您可以重写代码(您错过了$data上的访问说明符,所以我假设{{1} }):

private

答案 1 :(得分:0)

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