这个问题与我想要实现的目标非常相似,但正如该问题的几乎每个答案中的令人难以忍受的细节所表明的那样,这是一个糟糕的设计。
PHP, distinguish between internal and external class method call
这是我想要实现的目标:
跟踪对低事件配置表执行的所有操作,以便将更改传播到生产和 QA 数据库。 (配置表 = 配置存储在表中。)
这是我的问题的概要:
Yii 中的所有模型都继承自 CActiveRecord 类,该类提供了一些操作模型实例的方法。
让我们将它们分为两类:
- 非基元 - 触发 onBeforeDelete、onAfterFind、onAfterSave 等事件(例如: https://github.com/yiisoft/yii/blob/1.1.13/framework/db/ar/CActiveRecord.php#L1061 )
- 原语 - 直接创建和执行命令而不触发事件 - 即充当查询生成器。 (例如:https://github.com/yiisoft/yii/blob/1.1.13/framework/db/ar/CActiveRecord.php#L1684)
现在,这些原语也是公共(public)成员,因此可以由用户自行决定从类外部调用 - 并且它们将修改表而不触发任何事件。
这些是我提出的解决方案:
- 为所有开发人员制定仅使用非原始方法的准则。
- 将 CActiveRecord 封装在我自己的模型类中并仅公开非基元。
情况 1 更容易实现,但更容易出错,因为有时某些开发人员可能会忘记限制并使用原始方法。
情况 2 将要求我编写大量代码/方法来公开我希望使用的方法。另外,如果 Yii CActiveRecord 和我的 ActiveRecord 类没有相同的接口(interface),这可能会导致困惑。
在我看来,更好的解决方案是允许在内部使用原语,同时限制外部调用,即使用私有(private)/公共(public)访问说明符。 (这已经与我在情况 2 中提供的原因相矛盾,但这是我能想到的唯一解决方案。)由于我无法在不封装的情况下使用私有(private)/公共(public)说明符,并且我无法封装,所以我想区分方法,无论该函数是外部调用还是内部调用。 debug_backtrace 是一个可行的解决方案,但我来这里是为了一个更优雅、更少黑客的解决方案,或者一个明确的声明,表明这是不可能完成的。
最佳答案
首先,您应该退后一步思考为什么行为会有如此差异。您调用的非原始方法应该在模型实例上调用:
$ar = new Something();
$ar->update(...);
虽然您调用原语的方法应该在模型本身上调用:
Something::model()->updateByPk(...);
按理说,在第二种情况下引发事件是没有意义的,因为
- 您根本不应该直接使用
::model()
,并且 - 根据方法的不同,该操作可能会影响 PHP 中没有相应模型实例的多条记录
因此,寻求解决方案应该从回答以下两个问题开始:
- 在完美的世界中,在模型上调用任何方法时,您将如何收到通知? (显然,该方法需要是原始方法才能使调用有意义)。
- 在完美的情况下,如果某个操作影响未知(在 PHP 中)数量的记录,您将如何收到通知?
关于php - 根据对方法的外部或内部调用选择性地公开函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17082305/