3.3. smart_str API

这听起来似乎很奇怪,但是 C 语言几乎不提供操作字符串的方法(构建、连接、收缩、扩展、转换等等)。C 语言是低级通用语言,可以使用它来构建 API,去处理更多的特殊任务,比如字符串拼接。

注意

显然大家都知道我们谈论的是 ASCII 字符串,即字节。在这里没有 Unicode。

PHP 的smart_str 是一个 API,可以帮你构建字符串,特别是将字节块连接到字符串中。该 API 位于 PHP 的特殊 printf() APIzend_string的旁边,以帮助进行字符串管理。

smart_str VS smart_string

这里有两个结构:

  1. typedef struct {
  2. char *c;
  3. size_t len;
  4. size_t a;
  5. } smart_string;
  6. typedef struct {
  7. zend_string *s;
  8. size_t a;
  9. } smart_str;

就像你看到的,一个使用传统的 C 字符串(就像 char*/size_t),另一个使用 PHP 的特殊 zend_string 结构。

我们将详细介绍后者:smart_str,它和 zend_strings一起使用。这两个 API 实际上是一样的,只需注意一个以 smart_str_**()开头,另一个则以 smart_string_***()开头。不要混淆!

smart_str API 在 Zend/zend_smart_str.h 中会详细介绍。(还有 .c 文件) 。

警告

smart_str 不要和 smart_string 混淆。

基本的 API 使用

到目前为止,该 API 确实容易管理。你基本上可以堆栈分配smart_str,并将其指针传递给 smart_str_***() API函数,该函数可以为你管理嵌入式 zend_string。生成你的字符串,使用它,然后释放它。这并没有很强大,对吧?

嵌入式的 zend_string 的分配方式是永久地还是请求绑定的,取决于你使用的最后一个扩展 API 参数:

  1. smart_str my_str = {0};
  2. smart_str_appends(&my_str, "Hello, you are using PHP version ");
  3. smart_str_appends(&my_str, PHP_VERSION);
  4. smart_str_appends(&my_str, "\n");
  5. smart_str_appends(&my_str, "You are using ");
  6. smart_str_append_unsigned(&my_str, zend_hash_num_elements(CG(function_table)));
  7. smart_str_appends(&my_str, " PHP functions");
  8. smart_str_0(&my_str);
  9. /* 现在使用 my_str */
  10. PHPWRITE(ZSTR_VAL(my_str.s), ZSTR_LEN(my_str.s));
  11. /* 不要忘记释放它 */
  12. smart_str_free(&my_str);

我们在这里使用了简单的 API,, 扩展名以 _ex() 结尾,并且允许你在使用底层 zend_string 时,告知它你想要永久或者请求绑定的分配。例子:

  1. smart_str my_str = {0};
  2. smart_str_appends_ex(&my_str, "Hello world", 1); /* 1表示永久分配*/

然后,根据你想要追加的,使用正确的 API 调用。如果追加一个传统的 C 字符串,可以使用 smart_str_appends(smart_str *dst, const char *src)。如果使用一个二进制字符串,并且知道它的长度,则使用 smart_str_appendl(smart_str *dst, const char *src, size_t len)

不太特殊的smart_str_append(smart_str *dest, const zend_string *src)简单地将 zend_string 追加到你的 smart_str 字符串。如果你使用其他 smart_str,可使用smart_str_append_smart_str(smart_str *dst, const smart_str *src)将它们合并起来。

smart_str 具体技巧

  • 不要忘记调用 smart_str_0() 结束你的字符串。该函数在嵌入字符串的末尾增加了一个 NUL 字符,使它兼容 libc 字符串函数。
  • 当你完成后,不要忘记使用 smart_str_free() 释放你的字符串。
  • smart_str嵌入了 zend_string,并且允许共享,你之后可以在别处使用其引用计数。请访问 zend_string 专用章节了解更多。
  • 你可以使用 smart_str 分配。 看下 smart_str_alloc() 和朋友们。
  • smart_str 在 PHP 中大量地使用。例如,PHP 的printf() 函数 在内部使用了smart_str块。
  • smart_str 肯定你需要掌握的简单结构。