# smart_str API

这听起来似乎很奇怪，但是 C 语言几乎不提供操作字符串的方法（构建、连接、收缩、扩展、转换等等）。C 语言是低级通用语言，可以使用它来构建 API，去处理更多的特殊任务，比如字符串拼接。

> 注意
> 
> 显然大家都知道我们谈论的是 ASCII 字符串，即字节。在这里没有 Unicode。

PHP 的`smart_str` 是一个 API，可以帮你构建字符串，特别是将字节块连接到字符串中。该 API 位于 [PHP 的特殊 printf() API](http://www.phpinternalsbook.com/php7/internal_types/strings/printing_functions.html)和 [zend_string](http://www.phpinternalsbook.com/php7/internal_types/strings/zend_strings.html)的旁边，以帮助进行字符串管理。



## smart_str VS smart_string

这里有两个结构：

```
typedef struct {
    char *c;
    size_t len;
    size_t a;
} smart_string;

typedef struct {
    zend_string *s;
    size_t a;
} smart_str;

```

就像你看到的，一个使用传统的 C 字符串（就像 `char*/size_t`），另一个使用 PHP 的特殊 `zend_string` 结构。

我们将详细介绍后者：`smart_str`，它和 [zend_strings](http://www.phpinternalsbook.com/php7/internal_types/strings/zend_strings.html)一起使用。这两个 API 实际上是一样的，只需注意一个以 `smart_str_**()`开头，另一个则以 `smart_string_***()`开头。不要混淆！

`smart_str` API 在 [Zend/zend_smart_str.h](https://github.com/php/php-src/blob/509f5097ab0b578adc311c720afcea8de266aadd/Zend/zend_smart_str.h) 中会详细介绍。（还有 .c 文件） 。

> 警告
> 
> `smart_str` 不要和 `smart_string` 混淆。




## 基本的 API 使用

到目前为止，该 API 确实容易管理。你基本上可以堆栈分配`smart_str`，并将其指针传递给 `smart_str_***()` API函数，该函数可以为你管理嵌入式 `zend_string`。生成你的字符串，使用它，然后释放它。这并没有很强大，对吧？

嵌入式的 `zend_string` 的分配方式是[永久地还是请求绑定的](http://www.phpinternalsbook.com/php7/memory_management/zend_memory_manager.html)，取决于你使用的最后一个扩展 API 参数：
```
smart_str my_str = {0};

smart_str_appends(&my_str, "Hello, you are using PHP version ");
smart_str_appends(&my_str, PHP_VERSION);

smart_str_appends(&my_str, "\n");

smart_str_appends(&my_str, "You are using ");
smart_str_append_unsigned(&my_str, zend_hash_num_elements(CG(function_table)));
smart_str_appends(&my_str, " PHP functions");

smart_str_0(&my_str);

/* 现在使用 my_str */
PHPWRITE(ZSTR_VAL(my_str.s), ZSTR_LEN(my_str.s));

/* 不要忘记释放它 */
smart_str_free(&my_str);

```

我们在这里使用了简单的 API，, 扩展名以 `_ex()` 结尾，并且允许你在使用底层 `zend_string` 时，告知它你想要永久或者请求绑定的分配。例子：

```
smart_str my_str = {0};

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 专用章节](http://www.phpinternalsbook.com/php7/internal_types/strings/zend_strings.html)了解更多。
-   你可以使用 `smart_str` 分配。 看下 `smart_str_alloc()` 和朋友们。
-   `smart_str` 在 PHP 中大量地使用。例如，PHP 的[printf() 函数](http://www.phpinternalsbook.com/php7/internal_types/strings/printing_functions.html) 在内部使用了`smart_str`块。
-   `smart_str` 肯定你需要掌握的简单结构。
