PHP自定义的 printf 函数新用途-php教程

资源魔 39 0

【相干学习保举:php编程(视频)】

各人都晓得 libc 的 printf() 及其家族。本章节将具体引见 PHP 申明以及应用的许多克隆,它们的指标是甚么,为何应用它们,和什么时候应用它们。

留意

Libc 中对于 printf() 及其冤家的文档位于此处。

你晓得这些函数颇有用,但有时无奈提供足够的性能。另外,你晓得向 printf()增加格局字符串并不是易事,不便携性以及有平安危险。

PHP 增加了本人的相似于 printf 的函数,庖代了 libc 的,而且由外部开发者应用。他们次要增加新的格局,并应用 zend_string替代 char *等等,让咱们一同来看看。

正告

你必需把握 libc 默许printf() 格局。请浏览它们的文档。

留意

增加了这些函数以 庖代 libc 函数,象征着假如你应用了sprintf(),没有会应用到 libc 的sprintf(),而是 PHP 庖代了。除了了传统的 printf()外,其余内容均被交换。

传统用处

起首,你不该该应用 sprintf(),由于该函数没有执行任何反省,而且招致许多缓冲区溢犯错误。请防止应用它。

正告

尽可能防止应用 sprintf()

而后,你有一些抉择。

你晓得后果缓冲区的巨细

假如你晓得缓冲区巨细,snprintf() 或许 slprintf() 均可以应用。这些函数尽管正在前往上没有同,然而它们的性能是同样的。

这两个都是依据通报的格局来打印,而且无论发作甚么,城市经过一个NUL 字节 ‘\0’来终止你的缓冲区。 然而,snprintf() 前往能够应用的字符数,而slprintf()前往能够无效应用的字符数,因而能够检测太小的缓冲区以及字符串截断。这个没有管帐算最初的‘\0’

这里有个例子,以便你齐全明确:

char foo[8]; /* 8字符巨细的缓冲区 */
const char str[] = "Hello world"; /* 12个字符,蕴含 \0 */
int r;

r = snprintf(foo, sizeof(foo), "%s", str);
/* r = 11 ,即便这里只有7个可打印的字符可写入 foo */

/* foo 的值如今是 'H' 'e' 'l' 'l' 'o' ' ' 'w' '\0' */

snprintf() 没有是一个好用的函数,由于它没有容许反省最初的字符串截断。就像下面例子你看到的,显然“Hello world\0”没有适宜8字节的缓冲区,然而 snprintf() 依然前往11给你,这是 strlen("Hello world\0") 的值。你不方法反省字符串被截断了。

这是 slprintf()

char foo[8]; /* 8字符年夜的缓冲区 */
const char str[] = "Hello world"; /* 12个字符,蕴含 \0 */
int r;

r = slprintf(foo, sizeof(foo), "%s", str);
/* r = 7 ,由于7个可打印的字符被写入 foo */

/* foo 如今的值是 'H' 'e' 'l' 'l' 'o' ' ' 'w' '\0' */

应用 slprintf(),后果缓冲区 foo 蕴含齐全相反的字符串,然而现在前往值为7。7少于 “Hello world” 字符串的11个字符,以是你能够反省它被截断了:

if (slprintf(foo, sizeof(foo), "%s", str) < strlen(str)) {
    /* 发作字符串截断 */
}

记住:

  • 这两个函数老是以NUL终止字符串,不论能否截断。终极的字符串是平安的 C 字符串。
  • 只有 slprintf()会反省字符串截断。

这两个函数正在 main/snprintf.c 中有具体引见。

你没有晓得缓冲区巨细

如今假如你没有晓得后果缓冲区巨细,则需求静态调配一个,而且应用spprintf()。记住,你必需本人开释缓冲区。

这是例子:

#include <time.h>

char *result;
int r;

time_t timestamp = time(NULL);

r = spprintf(&result, 0, "Here is the date: %s", asctime(localtime(&timestamp)));

/* 如今后果相似:"Here is the date: Thu Jun 15 19:12:51 2017\n" */

efree(result);

spprintf() 前往被打印到后果缓冲区的字符数,没有包罗最初的‘\0’, 因而,你晓得调配给你的字节数(减一)是几何。

请留意,是应用 ZendMM(申请调配)调配的,因而应作为申请的一局部应用,并应用 efree() 而没有是free()开释。

留意

Zend 内存治理章节 (ZendMM) 具体引见若何经过 PHP 调配静态内存。

假如你想要限度缓冲区巨细,则将限度通报给第二个参数,假如你通报 0,象征着有限制:

#include <time.h>

char *result;
int r;

time_t timestamp = time(NULL);

/* 打印没有超越 10 个字节 ||调配超越 11 个字节 */
r = spprintf(&result, 10, "Here is the date: %s", asctime(localtime(&timestamp)));

/* r == 10,而且给后果调配 11 个字节 */

efree(result);

留意

尽可能没有要应用静态内存调配。这会影响执功能。假如有抉择,则选动态货仓旅馆调配缓冲区。

spprintf()写正在 main/spprintf.c 中。

那末 printf() 呢?

假如你需求 printf(),即打印格局化到输入流,则应用php_printf()。该函数正在外部应用 spprintf(),因而执举动态调配,以便将其发送到 SAPI 输入(正在 CLI 的状况下又称为 stdout),或输入缓冲区(CGI 缓冲区)后将其开释,用于其余 SAPI。

非凡的 PHP printf 格局

记住,PHP 经过本人设计,庖代了不少 libc 的 printf() 函数。你能够从浏览源代码中查看易于了解的参数解析 API。

这象征着解析算法的参数已齐全被重写,而且可能与你正在 libc 应用的没有同。即,正在年夜少数状况下,没有会存眷 libc 环境。

可能会应用非凡的格局,就像 “%I64” 打印64位 int,或许“%I32”。你也能够应用 “%Z” 去打印 zval(依据 PHP 规定转换为字符串),这是一个没有错的增补。

该格局化顺序也意识无量数,并打印 “INF”,或许将非数字打印为 “NAN”。

假如你谬误的申请格局化顺序打印一个 NULL 指针,libc 一定会解体,而 PHP 会将 “(null)” 作为后果字符串前往。

留意

假如正在打印中你看到神秘的 “(null)” 呈现,象征着你将 NULL 指针通报给了 PHP printf 系列函数之一。

Printf() 到 zend_strings

zend_string 作为 PHP 源代码里十分常见的构造,你可能需求 printf()zend_string,而没有是传统的 char *。为此,请应用strpprintf()

该 API 是 zend_string *strpprintf(size_t max_len, const char *format, ...) ,象征着前往zend_string 给你,而没有是你希冀的可打印字符数。不外你能够限度应用第一个参数来限度该数(通报 0 示意无量年夜);而且你肯定要记住将应用 Zend 内存治理调配 zend_string,并因而绑定以后申请。

显然,该格局 API 与下面看到的同享。

这有个例子:

zend_string *result;

result = strpprintf(0, "You are using PHP %s", PHP_VERSION);

/* 对后果做些甚么 */

zend_string_release(result);

对于 zend_ API 的正文

您可能会遇到 zend_spprintf()zend_strpprintf() 函数。这些与下面看到的齐全相反。

这只是 Zend 引擎以及 PHP 外围之间别离的一局部,这个细节对咱们其实不首要,由于正在源码中,一切内容都是夹杂正在一同的。


想理解更多编程学习,敬请存眷php培训栏目!

以上就是PHP自界说的 printf 函数新用处的具体内容,更多请存眷资源魔其它相干文章!

标签: php php开发教程 php开发资料 php开发自学 printf

抱歉,评论功能暂时关闭!