【发布时间】:2011-07-17 17:55:21
【问题描述】:
PHP 有像 Ruby 这样的符号吗?或者,我应该只使用字符串作为 PHP 关联数组中的键吗?
我猜这和问题Is there a Python equivalent to Ruby symbols?的答案是一样的
【问题讨论】:
PHP 有像 Ruby 这样的符号吗?或者,我应该只使用字符串作为 PHP 关联数组中的键吗?
我猜这和问题Is there a Python equivalent to Ruby symbols?的答案是一样的
【问题讨论】:
您可以使用简单的对象来产生类似 ruby 中的符号的效果。一些数据库函数有一个 FETCH_OBJECT 选项来模拟这种效果。
class StoreMe {
public $A;
public $B;
public $C;
public $D;
}
符号的主要优点是用作哈希键来优化性能和内存使用。由于 PHP 使用“写入时复制”来存储变量,因此字符串可能与 ruby 中的符号等价。但是 PHP 使用某种类型的转换表从哈希键中获取数组的索引。所以每个小数组都有一定的开销。
测试脚本
我编写了这个小脚本来测试 PHP 的内存占用。
error_log("Start: " . memory_get_usage());
$iterations = 10000;
$hash = [];
for ($i=0; $i<$iterations; $i++) {
$hash[] = [
"A" => "Test",
"B" => "Test",
"C" => "Test",
"D" => "Test",
];
}
error_log("String: " . memory_get_usage());
$hash = null;
error_log("Reset: " . memory_get_usage());
$hash = [];
for ($i=0; $i<$iterations; $i++) {
$hash[] = [
"Test",
"Test",
"Test",
"Test",
];
}
error_log("Raw: " . memory_get_usage());
$hash = null;
error_log("Reset: " . memory_get_usage());
$hash = [];
$copy = [
"Test",
"Test",
"Test",
"Test",
];
for ($i=0; $i<$iterations; $i++) {
$hash[] = $copy;
}
error_log("Copy: " . memory_get_usage());
$hash = null;
error_log("Reset: " . memory_get_usage());
$hash = [];
for ($i=0; $i<$iterations; $i++) {
$store = new StoreMe();
$store->A = "Test";
$store->B = "Test";
$store->C = "Test";
$store->D = "Test";
$hash[] = $store;
}
error_log("Object: " . memory_get_usage());
$hash = null;
$store = null;
error_log("Reset: " . memory_get_usage());
这里是 PHP 官方 Docker 镜像的结果。正确的值是以字节为单位的内存消耗。
PHP 5.6
Start: 225680
String: 8837400
Reset: 226088
Raw: 8837400
Reset: 226088
Object: 5580488
Reset: 1209264
PHP 7.0
Start: 355400
String: 4643840
Reset: 355400
Raw: 4643840
Reset: 355400
Copy: 884216
Reset: 355776
Object: 2127096
Reset: 478656
PHP 7.1
Start: 355336
String: 883776
Reset: 355336
Raw: 883776
Reset: 355336
Copy: 883776
Reset: 355336
Object: 2126656
Reset: 478216
结论
对象确实像预期的那样需要更少的内存。但是 PHP 5.6 似乎在使用对象进行垃圾收集方面存在问题。 PHP 7.1 的结果似乎是某种编译器优化,因为“写入时复制”和创建数组没有区别。
【讨论】:
不,PHP 没有这样的东西。 PHP 中最接近的方法是使用单引号字符串作为哈希键——只是为了确保其中没有“插值”。
几个例子:
$arr[key] — 在大多数情况下,这将像 $arr['key'] 一样工作,但有几个缺点:
a) 如果确实有一个已定义的常量(例如,define('key', 'rubbish')——您将访问$arr['rubish']。所以,这简直是不安全的。
b) 它会产生“PHP 通知”消息(除非通知被禁止)
$arr[@key] — 和以前一样,但没有通知。事实上,错误抑制在可维护性方面非常糟糕。
$arr["key"] — 绝对有效的方式,除非双引号字符串中有一些特殊符号。例如:"ab\ntc" != 'ab\ntc'、"ab$c" != 'ab$c' 等。但我相信,想到这种情况有点偏执。
$arr['key'] — 在我看来,这是最接近 Ruby 的 arr[:key],因为你可以在 PHP 中获得。
【讨论】:
如果您担心使用字符串作为数组键的重载以及数组被复制而不是每次作为引用传递的事实,我可以建议您使用stdClass,它基本上是一个对象类,可以动态修改,类似数组,但它的行为就像一个对象。
【讨论】:
PHP 没有符号,甚至常量在 PHP 中的工作方式也与在 ruby 中的工作方式大不相同。数组键必须是字符串或数字。您可以将字符串或数字分配给常量,然后“使用”该常量作为数组键。但是,常量在 PHP 中是静态的,因此这可能不是您想要的,需要更多“样板”代码,并且实际的数组键最终仍将是字符串或数字(基于常量的值)。
【讨论】:
关联数组是您唯一的选择。
【讨论】:
PHP 有可定义的常量,但在这种情况下这并不是很有用。
所以没有。使用字符串作为键。
【讨论】: