覆盖私有方法时的奇怪行为

2024-03-17

考虑下面的代码:

class foo {
    private function m() {
        echo 'foo->m() ';
    }
    public function call() {
        $this->m();
    }
}

class bar extends foo {
    private function m() {
        echo 'bar->m() ';
    }
    public function callbar() {
        $this->m();
    }
}

$bar = new bar;

$bar->call();
$bar->callbar();

现在,改变的可见性m()方法,我得到:
(+ for public, - for private)

Visibility              bar->call()    bar->callbar() 
======================================================
-foo->m(), -bar->m()    foo->m()       bar->m()
-foo->m(), +bar->m()    foo->m()       bar->m()
+foo->m(), -bar->m()    ERROR          ERROR
+foo->m(), +bar->m()    bar->m()       bar->m()

(protected似乎表现得像public).

我期望一切都像声明时一样public。但尽管foo->call() and bar->callbar()本质上是同一件事,它们会根据可见性产生不同的结果m() in foo and bar。为什么会出现这种情况?


继承/重写私有方法

在 PHP 中,子类中的方法(包括私有方法)是:

  • 已复制;原函数的范围保持不变。
  • 已替换(如果需要,可以“覆盖”)。

您可以通过以下代码看到这一点:

<?php
class A {
    //calling B::h, because static:: resolves to B::
    function callH() { static::h(); }
    private function h() { echo "in A::h"; }
}
class B extends A {
    //not necessary; just to make explicit what's happening
    function callH() { parent::callH(); }
}
$b = new B;
$b->callH();

现在如果你重写私有方法,它的新作用域将不是A,而是B,并且调用将会失败,因为A::callH()在范围内运行A:

<?php
class A {
    //calling B::h, because static:: resolves to B::
    function callH() { static::h(); }
    private function h() { echo "in A::h"; }
}
class B extends A {
    private function h() { echo "in B::h"; }
}
$b = new B;
$b->callH(); //fatal error; call to private method B::h() from context 'A'

调用方法

这里的规则如下:

  • Look in the method table of the actual class of the object (in your case, bar).
    • If this yields a private method:
      • 如果定义方法的作用域与调用函数的作用域相同并且与对象的类相同,则使用它。
      • 否则,请在父类中查找与调用函数具有相同作用域且具有相同名称的私有方法。
      • 如果没有找到满足上述要求之一的方法,则失败。
    • If this yields a public/protected method:
      • 如果方法的范围被标记为已更改,则我们可能已使用公共/受保护方法覆盖了私有方法。因此,在这种情况下,如果另外存在一个与调用函数范围定义的私有方法同名的方法,请改用该方法。
      • 否则,使用找到的方法。

结论

  1. (均为私人)对于bar->call(),范围call is foo。呼唤$this->m()引发在方法表中的查找bar for m,产生私有的bar::m()。然而,范围bar::m()与调用范围不同,foo。方法foo:m()在向上遍历层次结构时找到并使用它。
  2. (私人在foo,公开于bar) 范围call还是foo。查找产生一个公共bar::m()。然而,它的作用域被标记为已更改,因此在调用作用域的函数表中进行查找foo对于方法m()。这会产生一个私有方法foo:m()与调用范围具有相同的范围,因此使用它来代替。
  3. 这里没什么可看的,因为能见度降低而出错。
  4. (均为公开)范围call还是foo。查找产生一个公共bar::m()。它的范围没有被标记为已更改(它们都是公开的),所以bar::m()用来。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

覆盖私有方法时的奇怪行为 的相关文章

  • 删除多个对象 Amazon s3 PHP SDK

    我在一次删除多个对象时遇到问题 使用这个库 https github com aws aws sdk php laravel https github com aws aws sdk php laravel 我对使用该库的其他任何事情都没有
  • Laravel 输入:get() 不起作用

    我正在尝试在 Laravel 4 中使用 post 函数 我的表单有许多字段 在提交时 会转到控制器中的 post 函数 问题是 表单中的字段名称之间有空格 例如 Type 1 是输入的名称 中间有一个空格 现在 当我尝试通过执行以下操作来
  • 用于从 PHP 更新实时
  • 的 jQuery 插件
  • 有没有任何 jQuery 插件可以创建类似实时 feed 的东西推特主页 http www twitter com 使用 PHP 它从 MySQL 数据库获取数据 PHP 文件必须如何 Thanks 您确实不需要为此使用插件 您可以使用 j
  • 如何在 http POST 请求中发送 HTML 代码?

    我正在从 Google Web Toolkit 应用程序向 php 脚本发送 HTTP POST 请求 内容类型现在是 application x www form urlencoded 所以我可以将变量发送到 php 并使用 POST 在
  • 正则表达式删除外括号

    我一直在用这个 s s 正则表达式使用 PHP preg replace 函数删除外括号 在我上一个问题中了解更多信息正则表达式匹配除尾随空格之外的任何字符 https stackoverflow com questions 1076569
  • gform_after_submission 发布到第三方 API

    我正在尝试使用客户WordPress网站的functions php文件中的gform after submission钩子将这串信息发送到第三方API 此url由第三方客户提供 我需要将其与每次注册相匹配 这是我在 Functions p
  • 一起使用similar_text和strpos

    我想创建一个简单的搜索引擎 在用户输入中查找关键字 我知道我可以使用 strpos 来检查字符串中是否存在单词 但是 我希望用户能够拼写错误的单词 例如 userInput What year did George Washingtin b
  • 使用 6.0 API (Android) 从服务器发送和接收数据

    我真的很困惑 我正在尝试开发一个简单的功能 允许我从服务器发送和接收数据 操作如下 在一个活动中 我对服务器上的 PHP 文件执行 HTTP POST PHP 文件 获取我发送的数据 通常是字符串 并使用通过 http 发送的参数执行查询
  • 如何解决curl php中的HTTP/1.1 400 Bad Request

    我必须打一个 aspx来自 php 代码的页面 url 我试图使用curl 来访问 但出现以下错误并且 url 中没有空格 HTTP 1 1 400 Bad Request Content Type text html charset us
  • Apache mod_rewrite:在 Windows 计算机上使用 PHP 脚本的 RewriteMap 指令

    这已经让我发疯了 我似乎无法让 RewriteMap 指令适用于 Windows 上的 php 脚本 这是我的 httpd conf 文件中的相关片段
  • PHP mcrypt_decrypt - 我可以确定数据是否使用正确的密钥解密?

    我正在编写一个 php 脚本 并使用 mcrypt 来加密 解密任意数据 当我使用另一个密钥解密加密数据时 例如 我输入了错误的密码 输出当然不会被正确解密 如果使用了错误的密钥 我想显示一条错误消息 但我认为很难将输出字符串验证为正确的
  • 如何选中/取消选中单个单选按钮

    ssn byphone click function var ssn role document getElementById ssn byphone checked if ssn role true ssn div hide ssn by
  • 在 PHP 中用星号 (*) 提示或部分隐藏电子邮件地址

    我有这个邮件地址 email protected cdn cgi l email protection 如何将其转换为该邮件地址a email protected cdn cgi l email protection 我尝试使用strpos
  • 通过 CloudFlare 获取正确的访客 IP [重复]

    这个问题在这里已经有答案了 我正在使用其他人转售给我的 cPanel 这可能意味着我无法使用mod cloudflare 我想获取访问者的 IP 而不是 CloudFlare IP 我正在使用的代码部分 SERVER REMOTE ADDR
  • 使用 PHP 将数据添加到 json

    我使用 json decode 创建一个 json 对象 在浏览了一些元素之后 我想向其中添加子元素 我该怎么做呢 取决于您传递给的选项json decode http php net manual en function json dec
  • facebook graph api 确定用户是否喜欢 url

    如果用户当前登录 Facebook 并喜欢当前页面 我想显示不同的消息 我明白 FB Event subscribe edge create function response you like this 当用户喜欢该页面时 它将触发 但是
  • 如何处理 php 7 中的“gd-png: fatal libpng error: Read Error: truncated data”

    我使用 php 7 0 22 Ubuntu 17 04 当一些用户上传带有截断数据的 PNG 时 我使用 a imagecreatefrompng path 然后我崩溃了 Fatal error imagecreatefrompng gd
  • 运行 php 脚本的 Bash 脚本

    我有一个 php 脚本 我想使用 bash 脚本运行它 所以我可以使用 Cron 每分钟左右运行 php 脚本 据我所知 我需要创建 bash 脚本来处理 php 脚本 然后我才能使用 Cron 工具 计时器 到目前为止 我被告知我需要输入
  • 在 yii2 中搜索两个日期

    日期可以用不同的格式表示 表格本身看起来像这样 book varchar 250 NOT NULL date INT NOT NULL 现在我的问题是我无法在两个日期之间的范围内实现搜索 例如 有 5 本书 日期不同 但开始日期开始 在31
  • mysql_insert_id 带更新

    执行下面的查询后 我使用 PHP 函数mysql insert id 它总是给我0 UPDATE tbl training types SET fld serial serial no fld name training name fld

随机推荐

  • 如果使用了 waitFor,为什么杀死 JVM 也会终止其子进程?

    If waitFor不使用时 杀死JVM对其子进程没有影响 这是一个例子 重击脚本 usr bin env bash echo Sleeping gt log sleep 30 echo Wake up gt gt log Java代码 p
  • Java Applet 在 Safari 中沙箱化?

    自从升级到 Mavericks 后 如果从 Safari 使用 我们工作中的 Applet 就不再能够浏览文件 但在 Firefox 上仍然可以使用 Applet 处理文件上传 因此您可以想象这可能是一个问题 从 Safari 使用它时 我
  • 链接 ipython 小部件按钮和滑块值

    我试图弄清楚如何将按钮小部件控制的计数器的值链接到滑块小部件的值 这里的目标是使用 ipython 小部件创建一个简单的 类似 vcr 的界面 其中包含三个小部件 IntSlider和两个Button递增计数器和递减计数器 这就是我所拥有的
  • 如何将标题图像居中

    我有个问题 其他人问题的答案并没有解决我的问题 这是关于我的标题中的图像 代码如下 HTML div div img class center src http i imgur com jfDhpP5 png div div li a hr
  • 如何使用Python抓取需要先登录的网站

    首先 我认为值得一提的是 我知道有很多类似的问题 但没有一个对我有用 我是 Python html 和网络爬虫的新手 我正在尝试从需要先登录的网站中抓取用户信息 在我的测试中 我使用从 github 抓取我的电子邮件设置作为示例 主页是 h
  • 一个文件夹中包含 100 万个或更多文件,用于包含(缓存)[关闭]

    Closed 这个问题是无关 help closed questions 目前不接受答案 我有一个 理论 问题 看看我正在计划的解决方案是否有意义 我有一个脚本 可以从数据库中读取大量数据 包括设置 配置等 并将其构建在一起 针对每个注册用
  • 当我们给定中心点和半径大小时,如何绘制球体?

    我有一个像 1 2 2 23 2 3 3 6 3 4 5 的矩阵 每一行表示一个点 What I wish to do is like this I want to create a function which is given two
  • ExpandableListView 是否需要多个 viewHolder?

    我使用这个取景器是否错误 我在第 165 行收到 NPE 是否有明显的原因导致我失踪 如果我使用 ExpandableListView 是否需要组视图持有者和子视图持有者 我标记了第 165 行 以便让眼睛更舒服 多谢 我的可扩展列表视图正
  • Vuejs 3 webpack:vue-template-compiler 问题

    我正在尝试将 vuejs 3 集成到使用 webpack 的现有项目中 我读到了有关 vue loader 的内容 所以我正在尝试使用它 在官方文档中我有这样的内容 每次发布新版本的 vue 时 都会一起发布相应版本的 vue templa
  • Rails 其中 has_many 不为空

    My Campaign模型有很多Response 我想做的是这样的搜索Campaign where not responses nil 基本上返回所有有响应的活动的列表 最好的方法是什么 您可以通过查询来完成join Campaign jo
  • 有什么理由使用 isset() 吗?

    我为什么要使用if isset var 而不仅仅是if var 它似乎做了同样的事情 只是需要额外的处理 谢谢 Reason 原因是 isset 将返回布尔值 并且当您检查变量是否存在并继续时不会引发警告 此外 变量的值也有可能为零 fal
  • 为什么 C 会在 while 循环中卡住?

    当我编译并运行这段代码 它是一个更大的程序的一部分 时 Linux 已经完成了一半while循环 然后就停止工作 下面的代码打印time 0然后挂起 不执行任何其他操作 直到我暂停该进程 到底为什么它会打印time 0但不是下面的健全性检查
  • htaccess 中的重定向规则

    我的新闻有旧网址 例如http example com mynew 35 this is the title http example com mynew 35 this is the title 其中 35 是新闻的 ID 现在我的新网址
  • 列表理解和 len() 与简单的 for 循环

    我应该获取一个单词列表 并计算其中长度为 2 个或更多字符且第一个字符和最后一个字符相等的所有单词 我想出了两种可能的解决方案 result 0 for word in words if len word gt 2 and word 0 w
  • 是否可以将输入数组分散到参数中?

    因此 Promise all 将数组作为值传递到函数中 我更希望它将数组值作为参数传递 假设我有这个功能 function printData a b c console log a b c 我想 Promise all 1 2 3 the
  • GraphDB Free 8.8 Sparql INSERT 返回 400。不支持 INSERT?

    我正在使用 GraphDB Free 并尝试使用 sparql 将一些三元组插入到存储中 该查询看起来像一个简单的 INSERT Some Prefixes INSERT DATA subject predicate object 我使用
  • 无法访问文件“$libdir/plpgsql”:没有这样的文件或目录

    我不知所措 在本地 Postgres 服务器 postgres app Mac OS X 10 7 中创建存储过程时遇到问题 也是如此 psql psql 9 3 0 Type help for help dchaston CREATE O
  • MSSQL2008 - Pyodbc - 以前的 SQL 不是查询

    我无法弄清楚以下代码有什么问题 语法没问题 用 SQL Management Studio 检查 我可以按照我应该的方式访问 这样也可以工作 但由于某种原因 一旦我尝试通过 PyODBC 创建表 它就会停止工作 import pyodbc
  • 2D 模式搜索算法

    我需要学习二维模式搜索算法 非常感谢提示和链接 更重要的是 给定一个 M m n 矩阵 其值在 K 中 example 000000000000000001000000 010100010010 M K 0 1 010100010001 1
  • 覆盖私有方法时的奇怪行为

    考虑下面的代码 class foo private function m echo foo gt m public function call this gt m class bar extends foo private function