memory_get_usage()
memory_get_usage ([ bool
$real_usage
= false ] ) : int
PHP_FUNCTION(memory_get_usage) {
zend_bool real_usage = 0;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &real_usage) == FAILURE) {
RETURN_FALSE;
}
RETURN_LONG(zend_memory_usage(real_usage));
}
ZEND_API size_t zend_memory_usage(int real_usage)
{
#if ZEND_MM_STAT
if (real_usage) {
return AG(mm_heap)->real_size;
} else {
size_t usage = AG(mm_heap)->size;
return usage;
}
#endif
return 0;
}
implode
#define ZEND_HASH_FOREACH_VAL(ht, _val) \
ZEND_HASH_FOREACH(ht, 0); \
_val = _z;
#define ZEND_HASH_FOREACH(_ht, indirect) do { \
Bucket *_p = (_ht)->arData; \
Bucket *_end = _p + (_ht)->nNumUsed; \
for (; _p != _end; _p++) { \
zval *_z = &_p->val; \
if (indirect && Z_TYPE_P(_z) == IS_INDIRECT) { \
_z = Z_INDIRECT_P(_z); \
} \
if (UNEXPECTED(Z_TYPE_P(_z) == IS_UNDEF)) continue;
PHP_FUNCTION(implode)
{
zval *arg1, *arg2 = NULL, *arr;
zend_string *delim;
ZEND_PARSE_PARAMETERS_START(1, 2)
Z_PARAM_ZVAL(arg1)
Z_PARAM_OPTIONAL
Z_PARAM_ZVAL(arg2)
ZEND_PARSE_PARAMETERS_END();
if (arg2 == NULL) {
if (Z_TYPE_P(arg1) != IS_ARRAY) {
php_error_docref(NULL, E_WARNING, "Argument must be an array");
return;
}
delim = ZSTR_EMPTY_ALLOC();
arr = arg1;
} else {
if (Z_TYPE_P(arg1) == IS_ARRAY) {
delim = zval_get_string(arg2);
arr = arg1;
} else if (Z_TYPE_P(arg2) == IS_ARRAY) {
delim = zval_get_string(arg1);
arr = arg2;
} else {
php_error_docref(NULL, E_WARNING, "Invalid arguments passed");
return;
}
}
php_implode(delim, arr, return_value);
zend_string_release(delim);
}
PHPAPI void php_implode(const zend_string *delim, zval *arr, zval *return_value)
{
zval *tmp;
int numelems;
zend_string *str;
char *cptr;
size_t len = 0;
zend_string **strings, **strptr;
// 获取数组长度
numelems = zend_hash_num_elements(Z_ARRVAL_P(arr));
// 长度为0 直接返回空字符串
if (numelems == 0) {
RETURN_EMPTY_STRING();
// 长度为1 这里为什么用遍历?是因为HashTable中会有IS_UNDEF的Bucket
// 应该返回非IS_UNDEF的元素值,宏ZEND_HASH_FOREACH_VAL会为我没解决这个问题
} else if (numelems == 1) {
/* loop to search the first not undefined element... */
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(arr), tmp) {
// zval_get_string 函数会进行类型转换,无论zval是类型值都会转换为string
RETURN_STR(zval_get_string(tmp));
} ZEND_HASH_FOREACH_END();
}
strings = emalloc((sizeof(zend_long) + sizeof(zend_string *)) * numelems);
strptr = strings - 1;
// 计算需要为最后的str申请的内存大小
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(arr), tmp) {
//
if (Z_TYPE_P(tmp) == IS_LONG) {
zend_long val = Z_LVAL_P(tmp);
*++strptr = NULL;
((zend_long *) (strings + numelems))[strptr - strings] = Z_LVAL_P(tmp);
if (val <= 0) {
len++;
}
while (val) {
val /= 10;
len++;
}
} else {
*++strptr = zval_get_string(tmp);
len += ZSTR_LEN(*strptr);
}
} ZEND_HASH_FOREACH_END();
/* numelems can not be 0, we checked above */
// 向内存池申请一块非持久化的内存
str = zend_string_safe_alloc(numelems - 1, ZSTR_LEN(delim), len, 0);
cptr = ZSTR_VAL(str) + ZSTR_LEN(str);
*cptr = 0;
do {
if (*strptr) {
cptr -= ZSTR_LEN(*strptr);
memcpy(cptr, ZSTR_VAL(*strptr), ZSTR_LEN(*strptr));
zend_string_release(*strptr);
} else {
char *oldPtr = cptr;
char oldVal = *cptr;
zend_long val = ((zend_long *) (strings + numelems))[strptr - strings];
cptr = zend_print_long_to_buf(cptr, val);
*oldPtr = oldVal;
}
cptr -= ZSTR_LEN(delim);
// 添加delim
memcpy(cptr, ZSTR_VAL(delim), ZSTR_LEN(delim));
} while (--strptr > strings);
if (*strptr) {
memcpy(ZSTR_VAL(str), ZSTR_VAL(*strptr), ZSTR_LEN(*strptr));
zend_string_release(*strptr);
} else {
char *oldPtr = cptr;
char oldVal = *cptr;
zend_print_long_to_buf(cptr, ((zend_long *) (strings + numelems))[strptr - strings]);
*oldPtr = oldVal;
}
efree(strings);
RETURN_NEW_STR(str);
}
explode
explode ( string
$delimiter
, string$string
[, int$limit
] ) : array
limit
如果设置了limit
参数并且是正数,则返回的数组包含最多limit
个元素,而最后那个元素将包含string
的剩余部分。如果
limit
参数是负数,则返回除了最后的 –limit
个元素外的所有元素。如果
limit
是 0,则会被当做 1。
PHP_FUNCTION(explode)
{
zend_string *str, *delim;
zend_long limit = ZEND_LONG_MAX; /* No limit */
zval tmp;
ZEND_PARSE_PARAMETERS_START(2, 3)
Z_PARAM_STR(delim)
Z_PARAM_STR(str)
// limit为可选参数
Z_PARAM_OPTIONAL
Z_PARAM_LONG(limit)
ZEND_PARSE_PARAMETERS_END();
// delim不能为空字符串
if (ZSTR_LEN(delim) == 0) {
php_error_docref(NULL, E_WARNING, "Empty delimiter");
RETURN_FALSE;
}
// 初始化return_value
// PHP_FUNCTION中 return_value 是一个预定义的特殊的变量zval
// 函数不需要显示返回,默认返回return_value
array_init(return_value);
// str为空的情况
if (ZSTR_LEN(str) == 0) {
if (limit >= 0) {
// 初始化为一个空字符串类型的zval
ZVAL_EMPTY_STRING(&tmp);
// return_value[0] = ''
zend_hash_index_add_new(Z_ARRVAL_P(return_value), 0, &tmp);
}
return;
}
if (limit > 1) {
php_explode(delim, str, return_value, limit);
} else if (limit < 0) {
php_explode_negative_limit(delim, str, return_value, limit);
} else {
// limit == 0 的情况
// copy 一份str给tmp
// 设置return_value[0] = tmp
ZVAL_STR_COPY(&tmp, str);
zend_hash_index_add_new(Z_ARRVAL_P(return_value), 0, &tmp);
}
}
PHPAPI void php_explode(const zend_string *delim, zend_string *str, zval *return_value, zend_long limit)
{
char *p1 = ZSTR_VAL(str);
char *endp = ZSTR_VAL(str) + ZSTR_LEN(str);
// 查找下一个delim位置并返回指针
char *p2 = (char *) php_memnstr(ZSTR_VAL(str), ZSTR_VAL(delim), ZSTR_LEN(delim), endp);
zval tmp;
// 未找到
if (p2 == NULL) {
ZVAL_STR_COPY(&tmp, str);
// 设置return_value
// return_value[] = tmp
zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &tmp);
} else {
do {
// 取固定长的字符串
ZVAL_STRINGL(&tmp, p1, p2 - p1);
// 设置 return_value return_value[] = tmp
zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &tmp);
p1 = p2 + ZSTR_LEN(delim);
// 继续查找
p2 = (char *) php_memnstr(p1, ZSTR_VAL(delim), ZSTR_LEN(delim), endp);
} while (p2 != NULL && --limit > 1); // 当p2不为空 并且 limit未达到时继续
// 退出循环后,需要额外处理最后一个元素
if (p1 <= endp) {
ZVAL_STRINGL(&tmp, p1, endp - p1);
zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &tmp);
}
}
}