字符串管理zend_string任何程序都需要管理字符串,在这里,我们将详细介绍适合PHP需求的自定义解决方案:zend_string,每次PHP需要使用字符串时,都会使用zend_string结构。,php的字符串管理zend_string
字符串管理:zend_string 任何程序都需要管理字符串。在这里,我们将详细介绍适合 PHP 需求的自定义解决方案: 它添加了内存管理的功能,所以同一字符串可以在多个地方共享,而无需重复。另外,一些字符串是“内部的”,即“持久的”分配,并通过内存管理特殊管理,以便它们不会在多个请求中被销毁。之后,那些从Zend 内存管理获得永久分配。
结构和访问宏这里是简单的 struct _zend_string { zend_refcounted_h gc; zend_ulong h; size_t len; char val[1]; }; 如你所见,该结构嵌入了一个 如你所知,字符串知道其长度为 最终,该字符存储在 必须记住这种 struct hack,由于内存布局看起来像 C 字符位于 C 使用 zend_string API简单用例像 Zvals,你不需要手动操作 zend_string *str; str = zend_string_init("foo", strlen("foo"), 0); php_printf("This is my string: %s\n", ZSTR_VAL(str)); php_printf("It is %zd char long\n", ZSTR_LEN(str)); zend_string_release(str); 上面简单的例子为你展示了基本的字符串管理。应该为
然后,我们来显示字符串。我们使用
最后,我们使用
玩转 hash如果你需要访问哈希值,可使用 zend_string *str; str = zend_string_init("foo", strlen("foo"), 0); php_printf("This is my string: %s\n", ZSTR_VAL(str)); php_printf("It is %zd char long\n", ZSTR_LEN(str)); zend_string_hash_val(str); php_printf("The string hash is %lu\n", ZSTR_H(str)); zend_string_forget_hash_val(str); php_printf("The string hash is now cleared back to 0!"); zend_string_release(str); 字符串复制和内存管理 由此,当我们讨论“复制”一个 zend_string *foo, *bar, *bar2, *baz; foo = zend_string_init("foo", strlen("foo"), 0); /* 创建变量foo,值为“foo” */ bar = zend_string_init("bar", strlen("bar"), 0); /* 创建变量bar,值为"bar" */ /* 创建变量bar2,共享变量bar的值。 另外递增"bar"字符串的引用计数到2 */ bar2 = zend_string_copy(bar); php_printf("We just copied two strings\n"); php_printf("See : bar content : %s, bar2 content : %s\n", ZSTR_VAL(bar), ZSTR_VAL(bar2)); /* 在内存中复制"bar"字符串,创建变量 baz, 使 baz 单独拥有新创建的"bar"字符串 */ baz = zend_string_dup(bar, 0); php_printf("We just duplicated 'bar' in 'baz'\n"); php_printf("Now we are free to change 'baz' without fearing to change 'bar'\n"); /* 更改第二个"bar"字符串的最后一个字符, 变为"baz" */ ZSTR_VAL(baz)[ZSTR_LEN(baz) - 1] = 'z'; /* 当字符串改变时,忘记旧哈希值(如果已计算), 因此其哈希值必须更改并重新计数 */ zend_string_forget_hash_val(baz); php_printf("'baz' content is now %s\n", ZSTR_VAL(baz)); zend_string_release(foo); /* 销毁(释放)"foo"字符串 */ zend_string_release(bar); /* 递减"bar"字符串的引用计数到1 */ zend_string_release(bar2); /* 销毁(释放)bar和bar2变量中的"bar"字符串 */ zend_string_release(baz); /* 销毁(释放)"baz"字符串 */ 我们一开始仅分配 “foo” 和 “bar”。然后,我们创建 如果想要分离字符串,即想在内存中拥有该字符串的两个不同副本,我们必须使用 注意,我们忘记哈希值(如果它在之前已经计算,则不需要考虑其细节)。这是一个值得记住的好习惯。就像我们曾说过,如果 字符串操作
zend_string *FOO, *bar, *foobar, *foo_lc; FOO = zend_string_init("FOO", strlen("FOO"), 0); bar = zend_string_init("bar", strlen("bar"), 0); /* 将 zend_string 与 C 字符串文字进行比较 */ if (!zend_string_equals_literal(FOO, "foobar")) { foobar = zend_string_copy(FOO); /* realloc() 将 C 字符串分配到更大的缓冲区 */ foobar = zend_string_extend(foobar, strlen("foobar"), 0); /* 在重新分配的足够大的“FOO”之后,连接"bar" */ memcpy(ZSTR_VAL(foobar) + ZSTR_LEN(FOO), ZSTR_VAL(bar), ZSTR_LEN(bar)); } php_printf("This is my new string: %s\n", ZSTR_VAL(foobar)); /* 比较两个 zend_string */ if (!zend_string_equals(FOO, foobar)) { /*复制字符串并改为小写*/ foo_lc = zend_string_tolower(foo); } php_printf("This is FOO in lower-case: %s\n", ZSTR_VAL(foo_lc)); /* 释放内存 */ zend_string_release(FOO); zend_string_release(bar); zend_string_release(foobar); zend_string_release(foo_lc); 使用 zval 访问 zend_string现在你知道如何管理和操作
宏将允许你将 zval myval; zend_string *hello, *world; zend_string_init(hello, "hello", strlen("hello"), 0); /* 存储字符串到 zval */ ZVAL_STR(&myval, hello); /* 从 zval 的 zend_string 中读取 C 字符串 */ php_printf("The string is %s", Z_STRVAL(myval)); zend_string_init(world, "world", strlen("world"), 0); /* 将 zend_string 更改为 myval:将其替换为另一个 */ Z_STR(myval) = world; /* ... */ 你必须记住的是,以
每个以
还有一些你可能不需要的东西也存在。 PHP 的历史和经典的 C 字符串简单介绍一下。在 C 语言中,字符串是字符数组( 在 PHP 7 之前, 在任何可能的地方:使用 Interned zend_string在这里简单的介绍一下 interned 字符串。你在扩展开发中应该需要这样的概念。Interned 字符串也和 OPCache 扩展交互。 Interned 字符串是去重复的字符串。当与 OPCache 一起使用时,它还可以在请求之间循环使用。 假设你想要创建字符串“foo”。你更想做的是简单地创建一个新字符串“foo”: zend_string *foo; foo = zend_string_init("foo", strlen("foo"), 0); /* ... */ 但是有一个问题:字符串是不是在你需要之前已经创建了?当你需要一个字符串时,你的代码会在PHP生命中的某个时刻执行,这意味着在你需要完全相同的字符串(在我们的示例中为“ foo”)之前发生了一些代码。 Interned 字符串是关于要求引擎去探查 interned 字符串存储,并且如果它能找到你的字符串,会重用已经分配的指针。如果没有找到:创建一个新的字符串并“intern” 它,这使得它可用于 PHP 源代码的其他部分(其他扩展,引擎本身等)。 这里有个例子: zend_string *foo; foo = zend_string_init("foo", strlen("foo"), 0); foo = zend_new_interned_string(foo); php_printf("This string is interned : %s", ZSTR_VAL(foo)); zend_string_release(foo); 上面的代码创建了一个非常经典的新 你必须注意内存分配。Interned 字符串总是将 refcount 设为1,因为它们不必被引用,由于它们会和 interned 字符串缓冲区共享,因此不可被销毁。 例: zend_string *foo, *foo2; foo = zend_string_init("foo", strlen("foo"), 0); foo2 = zend_string_copy(foo); /* 递增 foo 的引用计数 */ /* 引用计数退回 1,即使现在字符串在三个不同的地方被使用 */ foo = zend_new_interned_string(foo); /* 这没有任何作用,因为 foo 是 interned */ zend_string_release(foo); /* 这没有任何作用,因为 foo2 是 interned*/ zend_string_release(foo2); /* 在流程结束时,PHP 将清除它的 interned 字符串缓冲区, 因此 free() 我们 "foo" 字符串本身 */ 这都是关于垃圾收集的。 当字符串是 interned,更改其 GC 标志以添加 事实上,此过程比这更为复杂。如果你使用的是请求处理中的 interned 字符串,那么该字符串肯定被 interned。但是,如果你是在 PHP 处理一个请求时使用 interned 字符串,那么该字符串只会在当前请求被 interned,并在之后会清理掉。如果你不使用 OPCache 扩展,那这一切都是有效的,有时你不应该使用它。 当使用 OPCache 扩展,如果你使用请求处理中的 interned 字符串,那么该字符串肯定被 interned ,并且和并行产生的每个 PHP 的进程或线程共享。另外,如果当你处理一个请求时使用 interned 字符串,该字符串也将由 OPCache 本身进行 interned,并且共享给并行产生的每个 PHP 进程或线程。 然后,在触发 OPCache 扩展时,会更改 Interned 字符串机制。OPCache 不仅允许从请求来的 interned 字符串,而且允许将它们共享给同一池的每个 PHP 进程。这样做是使用了共享内存。当保存一个 interned 字符串时,OPCache 也会添加 Interned 字符串可节省内存,因为在内存中,同样的字符串不会再被保存。但是当它经常需要查找 interned 字符串存储时,可能会浪费一些 CPU 时间,即使该进程如今已经优化了。作为一名扩展设计师,这是全局规则:
Interned 字符串详情请看 Zend/zend_string.c。 以上就是php的字符串管理 zend_string的详细内容,更多请关注 模板之家(www.mb5.com.cn) 其它相关文章! |