2
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
4

5 回答 5

13

ruby 相信赋予你做你想做的事的能力。它只是不会让你不经意间把你的脚踢掉——如果你想颠覆私有声明,你必须使用清楚地表明你正在这样做的语法。请注意,最终决定代码应该做什么或不应该做什么的人是使用库的人,而不是编写它的人。

于 2009-05-22T06:44:59.327 回答
5

我不能评论,因为低代表:/。

重新定义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 更多的是声明性目的:声明为 private 的方法是实现细节而不是 API 细节。不允许您意外地从外部发送消息。但是,如果他们认为合适的话,任何人仍然可以强行规避这一限制——以他们自己的名义。

于 2009-05-22T12:19:50.743 回答
4

如果你真的想保护 的实例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
于 2009-05-22T11:55:51.793 回答
1

至少你表达了 Widget 类的公共 API 是什么。

于 2009-05-22T06:41:02.843 回答
0

带回家的信息是:不要打扰。

Ruby 和 Python 一样,在沙盒方面绝对烂透了。如果您尝试锁定某些东西,那么总会有一些方法可以绕过它。在 Ruby 中获取私有属性的多种方法证明了我的观点。

为什么?因为它们被设计成那样。这两种语言的设计都是为了在运行时可以随意使用它们——这就是赋予它们强大功能的原因。通过封闭你的类,你剥夺了其他人使用 Ruby 元编程提供的能力。

Java有反射。C++ 有指针。甚至 Haskell 也有 unsafePerformIO。如果你想保护你的程序,你需要在操作系统级别上保护它,而不是使用语言。

于 2011-12-06T00:12:51.900 回答