【问题标题】:Call anonymous function from db从数据库调用匿名函数
【发布时间】:2013-12-05 06:56:16
【问题描述】:

我在我的项目中使用 Yii,并希望通过回调实现事件模型。我在 MySQL 中制作了“事件”模型,并希望在许多字段中存储匿名函数,例如,

**Event model in Yii**
id - int
name - varchar(255)
beforeEvent - text

在“afterEvent”字段中存储函数:

 function(){echo 'afterEvent #1';}

然后我获取所有事件并尝试调用“afterEvent”函数:

$events     = Event::model()->findAll();
foreach ($events as $event)
{
   $event->beforeEvent();                            
}

由于模型Event中没有那个方法,所以我做了代理方法

public function beforeEvent() { call_user_func($this->beforeEvent); }

出错的问题:

call_user_func() 期望参数 1 是一个有效的回调函数 'function(){ echo 'afterEvent of event #1 done'; }' 未找到或 无效的函数名


找到 1 个解决方案: 在代理方法 beforeEvent() 中使用 create_function 函数,如下所示:

public function beforeEvent(array $params){
$callback = create_function('$params', $this->beforeEvent);
$callback($params);
}

但在手册中说:

此函数在内部执行 eval(),因此具有相同的 eval() 等安全问题。此外,它的性能很差,而且 内存使用特性。如果您使用的是 PHP 5.3.0 或更新版本 应该使用本机匿名函数。

我们知道 eval 是邪恶的。在这种情况下如何使用匿名函数?

【问题讨论】:

  • 如果不能控制输入,那是邪恶的。这里的问题是,如果有人可以访问您的数据库,他们可以在网络服务器上执行任意代码。因此,无论您找到执行该代码的任何方法,问题仍然存在。

标签: php yii anonymous-function


【解决方案1】:

不要将代码存储在数据库中。事件发生后只能发生有限数量的事情,而这些事情的功能就在您的代码库中的某个地方。无需将它们复制到数据库中,然后尝试从那里评估它们。只需为您希望在某个事件中发生的事情存储一个标识符(例如sendEmail),然后在代码中为该操作调用适当的函数。

就能够重构代码而言,这也更加明智。想象一下,您必须重写一些会破坏存储在数据库中的一百万个回调函数的东西……这不是一个有趣的情况。数据是您的资产,代码正是使该资产可访问的原因。作为经验法则,请始终牢记于心“如果我在这个项目中获得成功,突然需要将规模扩大到 100 倍,我聘请了一家机构在一夜之间重写 more scalable platform X 中的所有内容,我可以继续使用相同的数据吗?” 因此,数据应该与平台无关。在数据库中存储可执行代码不是。

【讨论】:

  • 谢谢,想法 - “你想在特定事件中发生的事情的标识符(例如 sendEmail)”很棒。
【解决方案2】:

你是对的,你应该避免eval

我会使用其他类型的 PHP callables 并使用 serializebeforeEvent 列中序列化它们。

然后你就可以按照你的提议给他们打电话了:

public function beforeEvent() { call_user_func($this->beforeEvent); }

匿名函数还不能被序列化。

【讨论】:

    猜你喜欢
    • 2014-09-11
    • 1970-01-01
    • 2013-02-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多