为什么`substr([],1)`不返回“ rray”?

时间:2018-07-19 07:51:28

标签: php

Type Juggling

  

PHP在变量中不需要(或支持)显式类型定义   宣言;变量的类型取决于上下文   使用变量。

var_dump((string)[]);

输出:

NOTICE Array to string conversion on line number 3
string(5) "Array"

var_dump(substr([], 1));

输出:

WARNING substr() expects parameter 1 to be string, array given on line number 5
NULL

6 个答案:

答案 0 :(得分:1)

substr是一个内置函数,并进行类型检查internally。由于它期望一个字符串(Z_PARAM_STR(str)),因此会引发警告,并且该函数将立即返回null,而在类型检查之后不执行任何操作。

如果您希望获得与第一个示例相同的行为,也可以手动进行类型转换。

var_dump(substr((string)[], 1));

请记住,从数组到字符串的转换仍然是“无效”的,并会发出通知。甚至有一个rfc想要完全弃用这种行为。

答案 1 :(得分:1)

TL; DR

在解析类型参数时,PHP不会将数组变型成字符串。

长版

首先,将某些内容转换为字符串由函数_convert_to_string处理,而将数组转换为字符串则由代码处理:

case IS_ARRAY:
    zend_error(E_NOTICE, "Array to string conversion");
    zval_ptr_dtor(op);
    ZVAL_NEW_STR(op, zend_string_init("Array", sizeof("Array")-1, 0));
    break;

这是将数组转换为字符串,但还会发出通知,提示数组到字符串转换(此处的重要信息)。

我找不到明确的文档,但它似乎与以下事实有关:

1)zend_types.h处的源定义了以下类型常量:

#define IS_UNDEF                    0
#define IS_NULL                     1
#define IS_FALSE                    2
#define IS_TRUE                     3
#define IS_LONG                     4
#define IS_DOUBLE                   5
#define IS_STRING                   6
#define IS_ARRAY                    7

还有更多,但它们并不相关。

2)PHP内部使用Z_PARAM_STR读取字符串参数,那里的代码来回多了,但是归结为调用zend_parse_arg_str_weak

3)应该负责类型变戏法,但有以下几行:

if (EXPECTED(Z_TYPE_P(arg) < IS_STRING)) { 
    convert_to_string(arg);
    *dest = Z_STR_P(arg);
}

这意味着如果类型标识符小于字符串标识符,它将不调用convert_to_string(依次调用上述的_convert_to_string)。数组的类型标识符为7,大于字符串的6,因此不会发生类型变化。没有发出数组到字符串转换通知的事实也表明了这一点,这意味着根本不会调用类型转换代码。

对象将在函数zend_parse_arg_str_weak中得到特殊处理,该函数主要是调用对象具有的任何特殊字符串转换函数(例如__toString)。

答案 2 :(得分:0)

它返回rray,您只需要将(string)[]传递给substr而不是数组

$a = [];
$b = (string)$a;

echo substr($b, 1);

此代码的结果:https://3v4l.org/UqRqq

substr不会在内部 cast 变量进行内部字符串转换,因为它需要将string作为第一个参数并在字符串上进行操作,因此您必须在传递之前手动对其进行强制转换,否则它将只是说这不是字符串,它可能是一种帮助发现代码错误的机制,以防万一您无意将arrayobject传递给substr

答案 3 :(得分:0)

因为在substr函数中使用时它不是类型转换,因为substr以字符串作为参数并给出了数组。如果使用了

var_dump(substr((string)[], 1));

它将返回“ rray”;

答案 4 :(得分:0)

可能任何内置函数都可以拥有自己的强制类型算法。 因此,某些不触发[]"Array"转换的功能没什么特别的。

我只是推测,但是在C语言中,字符串和字符数组之间没有区别。因此(字符的)空数组的子字符串为null或空数组。 看起来substr将该行为泄露给了PHP。

答案 5 :(得分:0)

类型变戏法实验:

var_dump(substr("Hello" , 1));
Output : string(4) "ello" 

var_dump(substr(Hello , 1));
Output : string(4) "ello" 

var_dump(substr(10000 , 1));
Output : string(4) "0000"  

var_dump((string)[]); 
Output : Array

var_dump(substr((string)[], 1));  
Output : rray

var_dump(substr(false , 1));
Output : bool(false) 

var_dump(substr(1 , 1));
Output : bool(false) 

var_dump(substr(array() , 1)); 
Output : string(5) "Array" NULL substr() expects parameter 1 to be string, array given on line 6 

var_dump(substr(&&& , 1));
Output : syntax error, unexpected '&&' (T_BOOLEAN_AND) 

var_dump(substr(class , 1));
output : syntax error, unexpected 'class' (T_CLASS) 

var_dump(substr(BREAK , 1));
syntax error, unexpected 'break' (T_BREAK) 

结论(基于上述示例集):仅当PHP类型substr()不是保留字符串时,才将其转换为字符串。