- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我正在用 PHP 5.3 编写一个库,其中大部分是一个具有多个静态属性的类,这些属性由子类扩展以允许子类的零配置。
无论如何,这里有一个示例来说明我发现的特殊性:
<?php
class A {
protected static $a;
public static function out() { var_dump(static::$a); }
public static function setup($v) { static::$a =& $v; }
}
class B extends A {}
class C extends A {}
A::setup('A');
A::out(); // 'A'
B::out(); // null
C::out(); // null
B::setup('B');
A::out(); // 'A'
B::out(); // 'B'
C::out(); // null
C::setup('C');
A::out(); // 'A'
B::out(); // 'B'
C::out(); // 'C'
?>
现在,就我而言,这几乎是静态继承所需要的行为,但是,将 static::$a =& $v;
更改为 static::$ a = $v;
(无引用)你得到了我预期的行为,即:
'A'
'A'
'A'
'B'
'B'
'B'
'C'
'C'
'C'
谁能解释一下这是为什么?我无法理解引用如何以任何方式影响静态继承:/
更新:
基于 Artefacto's answer ,在基类(在本例中为 A)中具有以下方法,并在类声明产生上面标记为“期望”的行为后调用它,而无需在 setter 中通过引用分配,同时在使用 self 时保留结果: : 正如上面的“预期”行为。
/*...*/
public static function break_static_references() {
$self = new ReflectionClass(get_called_class());
foreach($self->getStaticProperties() as $var => $val)
static::$$var =& $val;
}
/*...*/
A::break_static_references();
B::break_static_references();
C::break_static_references();
/*...*/
最佳答案
静态属性 $a
在每个类中都是不同的符号,但在 $a = 1; 中,它实际上是同一个变量。 $b = &$a;
、$a
和 $b
是相同的变量(即,它们在相同的引用集上)。当进行简单赋值时($b = $v;
),两个符号的值都会改变;当通过引用进行赋值时 ($b = &$v;
),只有 $b
会受到影响。
首先,让我们了解静态属性是如何“继承”的。 zend_do_inheritance
迭代调用 inherit_static_prop
的父类(super class)静态属性:
zend_hash_apply_with_arguments(&parent_ce->default_static_members TSRMLS_CC,
(apply_func_args_t)inherit_static_prop, 1, &ce->default_static_members);
其中的定义是:
static int inherit_static_prop(zval **p TSRMLS_DC, int num_args,
va_list args, const zend_hash_key *key)
{
HashTable *target = va_arg(args, HashTable*);
if (!zend_hash_quick_exists(target, key->arKey, key->nKeyLength, key->h)) {
SEPARATE_ZVAL_TO_MAKE_IS_REF(p);
if (zend_hash_quick_add(target, key->arKey, key->nKeyLength, key->h, p,
sizeof(zval*), NULL) == SUCCESS) {
Z_ADDREF_PP(p);
}
}
return ZEND_HASH_APPLY_KEEP;
}
让我们翻译一下。 PHP 使用写时复制,这意味着如果值具有相同的内容,它将尝试共享值的相同实际内存表示 (zval)。 inherit_static_prop
为每个父类(super class)静态属性调用,以便可以将其复制到子类。 inherit_static_prop
的实现确保子类的静态属性将是 PHP 引用,无论父类的 zval 是否共享(特别是,如果父类(super class)有引用,子类将共享zval,如果不存在,zval 将被复制,新的 zval 将被引用;第二种情况我们在这里并不真正感兴趣。
所以基本上,当 A、B 和 C 形成时,$a
将是每个类的不同符号(即,每个类都有其属性哈希表,每个哈希表都有其属性$a
自己的条目),但底层 zval 将是相同的并且它将是一个引用。
你有这样的东西:
A::$a -> zval_1 (ref, reference count 3);
B::$a -> zval_1 (ref, reference count 3);
C::$a -> zval_1 (ref, reference count 3);
因此,当你做一个正常的作业时
static::$a = $v;
因为所有三个变量共享相同的 zval 及其引用,所以所有三个变量都将采用值 $v
。如果你这样做,结果会是一样的:
$a = 1;
$b = &$a;
$a = 2; //both $a and $b are now 1
另一方面,当你这样做的时候
static::$a =& $v;
您将打破引用集。假设您在 A 类中进行。您现在拥有:
//reference count is 2 and ref flag is set, but as soon as
//$v goes out of scope, reference count will be 1 and
//the reference flag will be cleared
A::$a -> zval_2 (ref, reference count 2);
B::$a -> zval_1 (ref, reference count 2);
C::$a -> zval_1 (ref, reference count 2);
类似的是
$a = 1;
$b = &$a;
$v = 3;
$b = &$v; //$a is 1, $b is 3
正如 Gordon 现已删除的答案中的特色,三个类的属性之间的引用集也可以通过在每个类中重新声明属性来打破:
class B extends A { protected static $a; }
class C extends A { protected static $a; }
这是因为如果属性被重新声明,它不会从父类(super class)复制到子类(参见条件 if (!zend_hash_quick_exists(target, key->arKey, key->nKeyLength, key->h) )
在 inherit_static_prop
中。
关于php - PHP (5.3) 的特殊行为、静态继承和引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3187124/
我想创建一个基于 jQuery 的非常简单的 html 编辑器(不是所见即所得)。 我的问题是如何制作 textarea或 div可能 在上面写一些文字 然后样式即标签(例如 some stuff 将
根据文档 isset 条款“测试此项目中是否已设置给定属性”。我不明白设置属性时 isset 返回 true 还是 false 在下面的代码片段中,当 env.JAVA_HOME 未设置时,java.
我正在尝试取消映射 o这是执行 :only 的默认命令( :help :only ),所以我尝试的第一件事是: nmap o 这种作品,除非我按 ,等待超过timeoutlen ms 然后按 o
我有以下型号: class MetaData(models.Model): created_at = models.DateTimeField(auto_now_add=True, auto_
下面列出了两行代码。两者对日期和时间的期望相同,但只有一个有效。我正在使用 R 3.1。 以下不起作用: DateTime2=strftime("08/13/2010 05:26:24.350", f
我有一个关于 C 代码的问题。 #include void foo(void){ int a; printf("%d\n",a); } void bar(void){
如果文件大小 > 8k,为什么读取的最后一个字节 = 0? private static final int GAP_SIZE = 8 * 1024; public static void main(
我有一个命令 Get-Testdata从不同来源检索测试数据并将这些数据存储到 PSObject以不同的值作为属性。然后将对象总数存储为数组,以便于操作、排序、计算等。 我的问题是我希望能够将这些数据
我正在使用 epoll 将大消息写入使用 HTTP 协议(protocol)的服务器。 fds 都设置为非阻塞,我正在使用边缘触发事件。我知道对于 EPOLLIN,我需要循环读取 fd,直到返回 EA
这对我来说听起来很奇怪: $test_1 = 'string'; $test_2 = '0'; var_dump(intval($test_1)); // Output: int 0 var_dump
这个问题在这里已经有了答案: Java: Integer equals vs. == (7 个回答) 7年前关闭。 请您解释以下行为。 public class EqAndRef { publ
Drupal 的行为到底是什么? 它为模块开发人员提供什么类型的服务层? 它映射到 jQuery.ready 的关系类型是什么? 最佳答案 长版:Drupal.behaviors 不仅仅是 jQuer
以下代码: dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ for (int i=0
人们可以将项目添加到数据库中。我让他们选择在此时添加它,或手动选择日期。 因此我得到了这个 HTML 结构。 (请注意,我将日期和时间选择器妥协为只有一行文本) Selec
创建了一个数据框: simpleDF is.na(simpleDF$vals) [1] TRUE TRUE FALSE > is.nan(simpleDF$vals) [1] FALSE TRU
我有一个大的 docker 镜像 A,我创建了一个新的 Dockerfile FROM A RUN rm /big-folder 我尝试使用以下方法构建图像: docker build --squas
我想知道以下情况下 JVM 的行为是什么: JVM 最小堆大小 = 500MB JVM 最大堆大小 = 2GB 操作系统有 1GB 内存 JVM启动后,程序运行一段时间后,使用内存超过1GB。我想知道
我们正在使用 spikeearrest 策略,但我们不了解其工作原理。峰值逮捕配置如下: 5pm 阅读文档,我们了解到,如果我们在一分钟内调用此流超过 5 次,则该策略将在第 5 次之后
我正在使用 cURL 发送 POST 请求: curl http://tarvos.local:8080/partial_Users/2 -d '{currentPage : 1, firstID :
我的表中有 6442670 条记录,我正在使用以下命令获取它们jdbctemplate 使用行号一次 1000000 个。以下是查询 select * from (select rowNum rn
我是一名优秀的程序员,十分优秀!