传统上,有两种表示字符串的方法:使用特殊字符发送字符串结尾的信号,或将字符串长度与字符串数据一起存储。C使用前者;字符串是以空字符结尾的字符数组。但是,这有一个限制,即C中的字符串不能在任何其他地方使用空字符,只能在末尾使用空字符。
为了克服这个限制,PHP引擎使用这个结构来表示字符串:
struct _zend_string {
zend_refcounted_h gc; /* refcount struct */
zend_ulong h; /* hash value */
size_t len; /* length of string */
char val[1]; /* array of chars (using struct "hack") */
};
如您所见,php开发人员选择存储字符串的长度及其数据。
现在,如果混合使用“二进制安全”和“非二进制安全”功能,会发生什么?
考虑在编写PHP扩展时可能使用的以下C代码:
zend_string *a = zend_string_init("a\0b", /* string length */ 3, 0);
zend_string *b = zend_string_init("a\0c", /* string length */ 3, 0);
if (strcmp(a->val, b->val) == 0) {
php_printf("Strings are equal!");
}
你认为会发生什么?此代码输出“字符串相等!”但他们显然不平等。自
strcmp
不考虑字符串的长度,它是一个非二进制安全函数。
大多数C的标准库字符串函数都可以被归类为“非二进制安全”函数,因为它依赖于空终止字符。
处理时
zend_string
在扩展代码中,应该使用zend字符串函数(
zend_string_*
)而不是C的字符串库。
要修复以前的代码:
if (zend_string_equals(a, b)) {
php_printf("Equal!");
} else {
php_printf("Not equal");
}
现在正确打印“不相等”。