Ruby 方法 instance_eval() 和 send() 不会否定私有可见性的好处吗?
Posted
技术标签:
【中文标题】Ruby 方法 instance_eval() 和 send() 不会否定私有可见性的好处吗?【英文标题】:Don't the Ruby methods instance_eval() and send() negate the benefits of private visibility? 【发布时间】:2010-10-28 03:38:18 【问题描述】:w = Widget.new # Create a Widget
w.send :utility_method # Invoke private method!
w.instance_eval utility_method # Another way to invoke it
w.instance_eval @x # Read instance variable of w
查看上面与 Widget 类相关的示例(如下),send 和 instance_eval 方法违反了私有和受保护可见性提供的所有保护。如果是这样,为什么还要在 Ruby 中使用私有和受保护的访问,因为无法保证您的定义会得到尊重?
class Widget
def x # Accessor method for @x
@x
end
protected :x # Make it protected
def utility_method # Define a method
nil
end
private :utility_method # And make it private
end
【问题讨论】:
类似问题:***.com/questions/2519136/… 【参考方案1】:ruby 相信赋予你做你想做的事的能力。 不经意间让你的脚离开并不容易 - 如果你想颠覆私有声明,你必须使用清楚地表明你正在这样做的语法。请注意,最终决定代码应该做什么或不应该做什么的人是使用库的人,而不是编写它的人。
【讨论】:
【参考方案2】:我不能评论,因为低代表:/。
重新定义send是没有用的,因为send只是__send__的通用名称(即下划线,下划线,“send”,下划线,下划线),也就是真正实现消息发送的方法。不建议重新定义任何 __method__。此外,其他人也可以重新打开课程并恢复定义:
class Widget
def send(method, *args, &block)
super
end
#and so on
end
在 Ruby 1.9 中,行为略有不同:#send 实际上尊重可见性,而 __send__ 没有。
Ruby 中的private 具有更多的声明性目的:声明为私有的方法是实现细节而不是API 细节。不允许您意外地从外部发送消息。但是,如果他们认为合适的话,任何人仍然可以强行规避这一限制——以他们自己的名义。
【讨论】:
【参考方案3】:如果您真的想要保护Widget
的实例,您可以这样做(以及其他一些东西;这里的代码不是完整的安全解决方案, 只是指示性的):
class Widget
def some_public_method
...
end
private
def utility_method
...
end
def send(method, *args, &block)
raise NotImplementedError.new('Widget is secure. Stop trying to hack me.')
end
def instance_eval(&block)
raise NotImplementedError.new('Widget is secure. Stop trying to hack me.')
end
class <<self
private
def class_eval(&block)
raise NotImplementedError.new('Widget is secure. Stop trying to hack me.')
end
end
end
Widget.freeze
【讨论】:
(但我不推荐它,因为 Widget 几乎与所有使用元编程的库都不兼容。) 有趣的潜在解决方案。你通过重新定义class_eval来防止什么?我不明白最后一节:“class class class 方法 class_eval,而不是实例方法。见***.com/questions/678037。我保护它的原因是你不能修改类来取消它的安全。您可能还应该冻结课程。 别忘了发送。即便如此,这也可以通过在require 'widget'
之前覆盖 Module#method_added
来预先破解。如果不冻结,覆盖 class_eval 不会给你带来太多好处,b/c 然后你仍然可以使用class Widget ... end
语法。简而言之,人们可以修改你的代码。学会接受它,它是一种解释性语言。【参考方案4】:
至少你表达了 Widget 类的公共 API 是什么。
【讨论】:
【参考方案5】:带回家的信息是:不要打扰。
Ruby 和 Python 一样,在沙盒方面绝对烂透了。如果您尝试锁定某些东西,那么总会有一些方法可以绕过它。在 Ruby 中获取私有属性的多种方法证明了我的观点。
为什么?因为它们被设计成那样。这两种语言的设计都是为了在运行时可以随意使用它们——这就是赋予它们强大功能的原因。通过封闭你的类,你剥夺了其他人使用 Ruby 元编程提供的能力。
Java 有反射。 C++ 有指针。甚至 Haskell 也有 unsafePerformIO。如果你想保护你的程序,你需要在操作系统级别保护它,而不是使用语言。
【讨论】:
以上是关于Ruby 方法 instance_eval() 和 send() 不会否定私有可见性的好处吗?的主要内容,如果未能解决你的问题,请参考以下文章