打印 Perl 对象方法的地址? (用于重新定义 Perl 类方法)

2024-01-01

I saw 如何重新定义 Perl 类方法? https://stackoverflow.com/questions/635212/how-can-i-redefine-perl-class-methods,所以我想通过一个例子更好地理解它是如何工作的。 (有关的:如何引用方法? - 珀尔蒙克斯 http://www.perlmonks.org/?node_id=62737)

如果我有一个对象$obj这是一些例子Class其中有Class::method, then $obj也有$obj->method;我假设在这种情况下简化的内存布局看起来像这样(在LaTeX 表生成器 http://www.tablesgenerator.com/latex_tables#;对于下面的一个,src here https://www.writelatex.com/read/gxwsnjzdxwbg):

...也就是说,在(比如说)地址 0x1000 我们有$obj->method,这将简单地(以某种方式)指向实际的Class::method定义,(比如说)位于 0x3500。

假设我有一个sub在主文件中的某处定义,somefunc(忽略表中的前缀 $),其定义以地址 0x2000 结束。

如果我“猴子补丁”/仅替换该方法$obj例如,我希望内存布局看起来像这样(src here https://www.writelatex.com/read/cphsjhfphvtk):

现在的事情是这样的 - 在下面的示例中(东西的命名比上表中的更独特),我实际上想替换整个类方法Demo::My::Functions::test_me使用主文件中定义的方法repl_test_me。我真的不知道对地址有何期望,因此我尝试使用以下方法来显示我认为的方法修补之前和之后的地址%p的说明符printf。代码输出如下:

$ perl cltest.pl 
Starting Demo::Main...
Orig test_me!
1: DMFo: 8e63dc0 DMFo->test_me 8e916f8 DMF::test_me 8e916e8 repl_test_me 8e91748
Orig test_me!
-- CODE --
Subroutine Demo::My::Functions::test_me redefined at cltest.pl line 59.
Repl test_me!
Repl test_me!
2: DMFo: 8e63dc0 DMFo->test_me 8e916f8 DMF::test_me 8dfb708 repl_test_me 8dfb6c8

这里奇怪的是,即使是在主文件中定义的函数,repl_test_me,更改地址 - 它不应该?!

所以,我显然没有打印我认为的函数地址 - 而且我认为每次调用我都有两个打印输出这一事实也证实了这一点,而我应该只有一个?

如何更改以下代码,以便打印出可以帮助我确认修补/重载是否按预期发生的地址?

这是代码,cltest.pl:

use v5.10.1;

package Demo::My::Functions;
$INC{'Demo/My/Functions.pm'} = 1;

use warnings;
use strict;

use base 'Class::Accessor';

__PACKAGE__->mk_accessors(qw(test_me));

sub test_me {
  my $self = shift;
  print("Orig test_me!\n");
  return 1;
}

sub test_also_me {
  my $self = shift;
  print("Orig test_also_me!\n");
  return 1;
}

sub new {
  my $class = shift;
  my $self = {};
  bless $self, $class;
  return $self;
}

############################################################
package Demo::Main;


use warnings;
use strict;
print("Starting Demo::Main...\n");

my $DMFA = Demo::My::Functions->new();

sub repl_test_me {
  my $self = shift;
  print("Repl test_me!\n");
  return 1;
}

# note: \&{$DMFA->test_me} calls!
printf("1: DMFo: %p DMFo->test_me %p DMF::test_me %p repl_test_me %p\n",
      $DMFA, \&{$DMFA->test_me}, \&{'Demo::My::Functions::test_me'}, \&repl_test_me
);

print("-- " . ref(\&{$DMFA->test_me}) . " --\n");

{
no strict 'refs';
#~ *Demo::My::Functions::test_me = sub {my $self = shift; print("ReplIN test_me!\n"); return 1; }; # OK
#~ *Demo::My::Functions::test_me = *repl_test_me; # overloads
*Demo::My::Functions::test_me = \&repl_test_me; # overloads
};

# test it:
$DMFA->test_me();

# output addr again:
printf("2: DMFo: %p DMFo->test_me %p DMF::test_me %p repl_test_me %p\n",
      $DMFA, \&{$DMFA->test_me}, \&{'Demo::My::Functions::test_me'}, \&repl_test_me
);

对象没有方法;类做。对象只是一个带有与其关联的包的变量。

$ perl -MDevel::Peek -E'$o={}; Dump($o); bless($o); Dump($o); say \%main::'
SV = IV(0x26c2360) at 0x26c2370
  REFCNT = 1
  FLAGS = (ROK)
  RV = 0x269a978
  SV = PVHV(0x26a0400) at 0x269a978
    REFCNT = 1
    FLAGS = (SHAREKEYS)
    ARRAY = 0x0
    KEYS = 0
    FILL = 0
    MAX = 7
SV = IV(0x26c2360) at 0x26c2370
  REFCNT = 1
  FLAGS = (ROK)
  RV = 0x269a978
  SV = PVHV(0x26a0400) at 0x269a978
    REFCNT = 1
    FLAGS = (OBJECT,SHAREKEYS)
    STASH = 0x269a7f8   "main"
    ARRAY = 0x0
    KEYS = 0
    FILL = 0
    MAX = 7
HASH(0x269a7f8)    # Address of the main package.

所以真正的布局是

                +---------+
                |         |
                |         v
+-----------+   |   +-----------+
| Reference |   |   | 0x269a7f8 |
| 0x26c2370 |   |   | Package   |
+-----------+   |   +-----------+
      |         |         |
  References    |     Contains
      |         |         |
      v         |         v
+-----------+   |   +-----------+
| Hash      |   |   | 0xXXXXXXX |
| 0x269a978 |   |   | Method    |
+-----------+   |   +-----------+
      |         |
Blessed into    |
      |         |
      +---------+

更改包会影响使用该包的所有对象。

$ perl -E'
   sub f { "a" }
   my $o = bless({});
   say join " ", \&f, $o->can("f"), $o->f;
   *f = sub { "b" };
   say join " ", \&f, $o->can("f"), $o->f;
'
CODE(0x311c680) CODE(0x311c680) a
CODE(0x3126f60) CODE(0x3126f60) b
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

打印 Perl 对象方法的地址? (用于重新定义 Perl 类方法) 的相关文章

  • getoptions 函数 perl 多值不起作用

    具有以下 getoptions 功能 iifiles 参数是可选的 如果提供的话它可以是一对多 但是当我运行此函数时收到错误消息 选项规范错误 Perl 在Solaris 10 上运行 不确定需要为iiles 提供哪些多值选项 GetOpt
  • Perl:管理 Windows 上的路径编码

    我正在努力处理包含非英文字符的路径 Activestate Perl Windows XP 如何打开 写入 复制等位于包含希腊语 俄语 法语重音字符的路径中的文件 假设我要将 text txt 文件复制到的目录是 C Documents a
  • Perl 拆分和正则表达式

    我有以下字符串 100 California Grown Olives Water Salt And Ferrous Gluconate An Iron Derivative asasd sadasda 我想把它分开 but only if
  • 通过 TFS 构建服务执行时 MSBuild 找不到引用

    我有一个参考 Telerik 程序集的解决方案 引用的版本已安装在构建服务器上 问题是 持续集成构建总是成功的 直到我升级解决方案和构建服务器上的 Telerik 程序集 现在构建无法提供经典的 无法解析此引用 我检查了我的解决方案 一切都
  • Java 相当于 Perl 的 s/// 运算符?

    我有一些代码正在从 Perl 转换为 Java 它大量使用了正则表达式 包括s 操作员 我已经使用 Perl 很长时间了 但仍然习惯 Java 的做事方式 特别是 字符串似乎更难使用 有谁知道或有一个完全实现的Java函数s 这样它就可以处
  • 是否有与 pdl2(或 Devel::REPL)中的 perl 调试器“x”等效的东西?

    我在用pdl2 the PDL http p3rl org PDLshell 也作为我的默认 Perl 交互式 shell 它加载所有不错的插件Devel REPL http search cpan org perldoc Devel 3a
  • Web 开发中的 Perl [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • Perl 中的线程定时循环

    本质上 我希望有一个高优先级线程 它以给定的时间间隔 此处为 0 5 毫秒 运行并中断 一切 执行一个短任务 然后返回 睡眠 状态 使用 Ubuntu 11 04 和 perl v5 10 1 问题是 虽然我得到了某种结果 但我不确定是否有
  • 如何使用 Perl 在 Unix 中获取文件创建时间

    如何使用 perl 在 unix 中获取文件创建时间 我有这个命令显示文件的最后修改时间 perl MPOSIX le print strftime d b Y H M localtime lstat 9 for ARGV file txt
  • “foreach”循环中会发生什么样的本地化?

    来自 perldocperlsyn http perldoc perl org perlsyn html Foreach Loops关于 Foreach 循环的主题 如果变量之前是 用 my 声明 它使用 变量而不是全局变量 但它仍然局限于
  • 从具有不同活动 perl 版本的另一个 perl 脚本调用 perl 函数

    我们有两个版本的 Active perl 5 6 和 5 24 我们有必须在 Active perl 5 24 版本 采用 TLS 1 2 版本 上执行的 Web 服务 并且需要从 Active perl 5 6 版本调用 我们使用的是wi
  • 从 HoA 值中获取独特元素并打印

    我有一个 HoA 其中包含某些值 我只需要 HoA 中的独特元素 预期结果 Key 1 Element ABC DEF Key 2 Element XYZ RST Key 3 Element LMN 下面是我的脚本 usr bin perl
  • 将非 GAC 引用添加到项目中

    每次我在 Visual Studio 2008 中添加对 GAC 中的 Web 项目的引用时 它都会将该引用添加为 GAC 引用 并且不会将该文件复制到我的 bin 目录中 但出于部署目的 我想将引用添加为非 GAC 引用 以便将 dll
  • Log4Perl 将多个程序的日志记录捆绑到一个日志中

    CPAN 上是否有任何 Logger 它允许我将多个程序的日志捆绑到一个文件中 并在两个程序同时运行并并行调用 log4Perl 时同步并行日志记录 背景是我使用一个自定义附加程序来写入电子邮件 我想将所有电子邮件捆绑在一个文件中作为备份
  • 如何在 Perl 中将多个哈希值合并为一个哈希值?

    在 Perl 中 我如何得到这个 VAR1 999 gt 998 gt 908 906 0 998 907 VAR1 999 gt 991 gt 913 920 918 998 916 919 917 915 912 914 VAR1 99
  • perl:正确的“内容类型”格式以返回“图像数据 uri”

    我有一个模板angularjs期待着image data uri由通过调用的服务器调用返回src的属性img模板的元素 img width 200px height 200px src http localhost 3000 returni
  • 在 Perl 中查找标量变量的数据类型

    我有一个接受用户输入的函数 输入可以是整数 浮点数或字符串 我有三个重载函数 应该根据输入数据的数据类型调用它们 例如 如果用户输入一个整数 比如100 则应该调用具有整数参数的函数 如果用户输入字符串 例如 100 则应调用具有字符串参数
  • Perl 如何存储/处理非常大的数字?是否应该使用模块来代替 Perl 的默认处理方法?

    我需要添加 50 位数字 因此我将它们作为 字符串 处理 并编写了自己的函数将它们相加 后来 为了它的地狱 我尝试了这个 readFile shift ARGV sub readFile my file shift contains a b
  • 找不到参考组件 Microsoft.CSharp

    我在 Visual Studio 2010 启动的 C 项目上发现了这个问题 当我转到 2008 年使用的另一台 PC 时 我打开 project csproj 需要 get 或 set 访问器 和警告 找不到引用的组件 Microsoft
  • MSBuild 命令行 - 添加 dll 引用

    我使用 makefile 来编译我的 C 项目 在这个makefile中 我创建了一个库tools dll 调用csc exe OK 现在 我想在我的项目中使用这个 dll 由于某些原因 我必须使用使用 csproj 文件的 MSBuild

随机推荐