草庐IT

php - "Overloading"PHP 中的私有(private)方法

coder 2024-01-01 原文

我知道我不能在 PHP 中重载方法。而且,据我所知,类中的 private 方法对于扩展基类的类是不可见的。那么为什么这不起作用?

class Base {
  private function foo($arg) {
     print "Base $arg";
  }
}

class Child extends Base {
  public function foo() {
     print "Child";
  }
}

$c = new Child;
print $c->foo();

错误:

PHP 严格标准:Child::foo() 声明应与/var/www/boludo.php 第 17 行中的 Base::foo($arg) 兼容

我假设 foo($arg) 方法在 Child 类中是不可见的,因为它是 private。所以,我没有重载 foo,我只是创建了一个名为 foo 的方法。

最佳答案

要修复通知,只需将 Child 中的 foo() 更改为

public function foo($arg = null) {

关于“为什么这不起作用”的问题:

PHP 中的可见性完全与运行时访问有关。它不会影响您如何扩展/组合/重载类和方法。从子类型中的父类(super class)型中放松私有(private)方法的可见性将在子类型中添加一个单独的方法,而无法访问父类(super class)型中的相同命名方法。但是,PHP 将为这些假设一个父子关系。但这并没有引起通知。至少,不是靠它自己。

您收到通知的原因是您还试图更改方法签名。您的 foo() 不再需要将 $arg 传递给它。当您假定方法之间存在父子关系时,这是一个问题,因为 Liskov Substitution Principle声明“如果 S 是 T 的子类型,则类型 T 的对象可以替换为类型 S 的对象” 而不会破坏程序。换句话说:如果您有使用 Base 的代码,您应该能够将 Base 替换为 Child 并且该程序仍然可以正常工作它正在使用 Base

假设您的 Base 也有一个公共(public)方法 bar()

class SomeClientUsingBase
{
    public function doSomethingWithBase(Base $base)
    {
        $result = $base->bar();
        // …

现在想象 Child 更改 bar() 以需要一个参数。如果您随后将 BaseChild 传递给客户端,您将破坏客户端,因为客户端调用 $base->bar();没有争论。

显然,您可以更改客户端以传递参数,但代码实际上取决于 Child 定义方法的方式,因此 Typehint 是错误的。事实上,Child 不是 Base,因为它的行为不像 Base。那就是破坏继承。

现在有趣的是,如果您从 foo() 中删除 $arg,从技术上讲您并没有违反 LSP,因为客户端仍然可以工作。这里的通知是错误的。在以前使用 Base 的客户端中调用 $base->foo(42) 仍然可以使用 Child,因为 Child 可以简单地忽略参数。但是 PHP 希望您将参数设为可选。

请注意,LSP 也适用于方法可能返回的内容。 PHP 只是不在签名中包含返回类型,所以您自己已经考虑到了这一点。您的方法必须返回父类(super class)型返回的内容或行为等效的内容。

关于php - "Overloading"PHP 中的私有(private)方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18288774/

有关php - "Overloading"PHP 中的私有(private)方法的更多相关文章

  1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

    我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

  2. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  3. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  4. ruby - 其他文件中的 Rake 任务 - 2

    我试图在一个项目中使用rake,如果我把所有东西都放到Rakefile中,它会很大并且很难读取/找到东西,所以我试着将每个命名空间放在lib/rake中它自己的文件中,我添加了这个到我的rake文件的顶部:Dir['#{File.dirname(__FILE__)}/lib/rake/*.rake'].map{|f|requiref}它加载文件没问题,但没有任务。我现在只有一个.rake文件作为测试,名为“servers.rake”,它看起来像这样:namespace:serverdotask:testdoputs"test"endend所以当我运行rakeserver:testid时

  5. ruby-on-rails - Ruby net/ldap 模块中的内存泄漏 - 2

    作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代

  6. ruby - Facter::Util::Uptime:Module 的未定义方法 get_uptime (NoMethodError) - 2

    我正在尝试设置一个puppet节点,但ruby​​gems似乎不正常。如果我通过它自己的二进制文件(/usr/lib/ruby/gems/1.8/gems/facter-1.5.8/bin/facter)在cli上运行facter,它工作正常,但如果我通过由ruby​​gems(/usr/bin/facter)安装的二进制文件,它抛出:/usr/lib/ruby/1.8/facter/uptime.rb:11:undefinedmethod`get_uptime'forFacter::Util::Uptime:Module(NoMethodError)from/usr/lib/ruby

  7. ruby-on-rails - rails : "missing partial" when calling 'render' in RSpec test - 2

    我正在尝试测试是否存在表单。我是Rails新手。我的new.html.erb_spec.rb文件的内容是:require'spec_helper'describe"messages/new.html.erb"doit"shouldrendertheform"dorender'/messages/new.html.erb'reponse.shouldhave_form_putting_to(@message)with_submit_buttonendendView本身,new.html.erb,有代码:当我运行rspec时,它失败了:1)messages/new.html.erbshou

  8. ruby-on-rails - 由于 "wkhtmltopdf",PDFKIT 显然无法正常工作 - 2

    我在从html页面生成PDF时遇到问题。我正在使用PDFkit。在安装它的过程中,我注意到我需要wkhtmltopdf。所以我也安装了它。我做了PDFkit的文档所说的一切......现在我在尝试加载PDF时遇到了这个错误。这里是错误:commandfailed:"/usr/local/bin/wkhtmltopdf""--margin-right""0.75in""--page-size""Letter""--margin-top""0.75in""--margin-bottom""0.75in""--encoding""UTF-8""--margin-left""0.75in""-

  9. ruby-on-rails - Rails 3 中的多个路由文件 - 2

    Rails2.3可以选择随时使用RouteSet#add_configuration_file添加更多路由。是否可以在Rails3项目中做同样的事情? 最佳答案 在config/application.rb中:config.paths.config.routes在Rails3.2(也可能是Rails3.1)中,使用:config.paths["config/routes"] 关于ruby-on-rails-Rails3中的多个路由文件,我们在StackOverflow上找到一个类似的问题

  10. ruby - 具有身份验证的私有(private) Ruby Gem 服务器 - 2

    我想安装一个带有一些身份验证的私有(private)Rubygem服务器。我希望能够使用公共(public)Ubuntu服务器托管内部gem。我读到了http://docs.rubygems.org/read/chapter/18.但是那个没有身份验证-如我所见。然后我读到了https://github.com/cwninja/geminabox.但是当我使用基本身份验证(他们在他们的Wiki中有)时,它会提示从我的服务器获取源。所以。如何制作带有身份验证的私有(private)Rubygem服务器?这是不可能的吗?谢谢。编辑:Geminabox问题。我尝试“捆绑”以安装新的gem..

随机推荐