xref: /PHP-7.4/ext/standard/type.c (revision 9e9407c2)
1 /*
2    +----------------------------------------------------------------------+
3    | PHP Version 7                                                        |
4    +----------------------------------------------------------------------+
5    | Copyright (c) The PHP Group                                          |
6    +----------------------------------------------------------------------+
7    | This source file is subject to version 3.01 of the PHP license,      |
8    | that is bundled with this package in the file LICENSE, and is        |
9    | available through the world-wide-web at the following url:           |
10    | http://www.php.net/license/3_01.txt                                  |
11    | If you did not receive a copy of the PHP license and are unable to   |
12    | obtain it through the world-wide-web, please send a note to          |
13    | license@php.net so we can mail you a copy immediately.               |
14    +----------------------------------------------------------------------+
15    | Author: Rasmus Lerdorf <rasmus@php.net>                              |
16    +----------------------------------------------------------------------+
17 */
18 
19 #include "php.h"
20 #include "php_incomplete_class.h"
21 
22 /* {{{ proto string gettype(mixed var)
23    Returns the type of the variable */
PHP_FUNCTION(gettype)24 PHP_FUNCTION(gettype)
25 {
26 	zval *arg;
27 	zend_string *type;
28 
29 	ZEND_PARSE_PARAMETERS_START(1, 1)
30 		Z_PARAM_ZVAL(arg)
31 	ZEND_PARSE_PARAMETERS_END();
32 
33 	type = zend_zval_get_type(arg);
34 	if (EXPECTED(type)) {
35 		RETURN_INTERNED_STR(type);
36 	} else {
37 		RETURN_STRING("unknown type");
38 	}
39 }
40 /* }}} */
41 
42 /* {{{ proto bool settype(mixed &var, string type)
43    Set the type of the variable */
PHP_FUNCTION(settype)44 PHP_FUNCTION(settype)
45 {
46 	zval *var;
47 	zend_string *type;
48 	zval tmp, *ptr;
49 
50 	ZEND_PARSE_PARAMETERS_START(2, 2)
51 		Z_PARAM_ZVAL(var)
52 		Z_PARAM_STR(type)
53 	ZEND_PARSE_PARAMETERS_END();
54 
55 	ZEND_ASSERT(Z_ISREF_P(var));
56 	if (UNEXPECTED(ZEND_REF_HAS_TYPE_SOURCES(Z_REF_P(var)))) {
57 		ZVAL_COPY(&tmp, Z_REFVAL_P(var));
58 		ptr = &tmp;
59 	} else {
60 		ptr = Z_REFVAL_P(var);
61 	}
62 	if (zend_string_equals_literal_ci(type, "integer")) {
63 		convert_to_long(ptr);
64 	} else if (zend_string_equals_literal_ci(type, "int")) {
65 		convert_to_long(ptr);
66 	} else if (zend_string_equals_literal_ci(type, "float")) {
67 		convert_to_double(ptr);
68 	} else if (zend_string_equals_literal_ci(type, "double")) { /* deprecated */
69 		convert_to_double(ptr);
70 	} else if (zend_string_equals_literal_ci(type, "string")) {
71 		convert_to_string(ptr);
72 	} else if (zend_string_equals_literal_ci(type, "array")) {
73 		convert_to_array(ptr);
74 	} else if (zend_string_equals_literal_ci(type, "object")) {
75 		convert_to_object(ptr);
76 	} else if (zend_string_equals_literal_ci(type, "bool")) {
77 		convert_to_boolean(ptr);
78 	} else if (zend_string_equals_literal_ci(type, "boolean")) {
79 		convert_to_boolean(ptr);
80 	} else if (zend_string_equals_literal_ci(type, "null")) {
81 		convert_to_null(ptr);
82 	} else {
83 		if (ptr == &tmp) {
84 			zval_ptr_dtor(&tmp);
85 		}
86 		if (zend_string_equals_literal_ci(type, "resource")) {
87 			php_error_docref(NULL, E_WARNING, "Cannot convert to resource type");
88 		} else {
89 			php_error_docref(NULL, E_WARNING, "Invalid type");
90 		}
91 		RETURN_FALSE;
92 	}
93 
94 	if (ptr == &tmp) {
95 		zend_try_assign_typed_ref(Z_REF_P(var), &tmp);
96 	}
97 	RETVAL_TRUE;
98 }
99 /* }}} */
100 
101 /* {{{ proto int intval(mixed var [, int base])
102    Get the integer value of a variable using the optional base for the conversion */
PHP_FUNCTION(intval)103 PHP_FUNCTION(intval)
104 {
105 	zval *num;
106 	zend_long base = 10;
107 
108 	ZEND_PARSE_PARAMETERS_START(1, 2)
109 		Z_PARAM_ZVAL(num)
110 		Z_PARAM_OPTIONAL
111 		Z_PARAM_LONG(base)
112 	ZEND_PARSE_PARAMETERS_END();
113 
114 	if (Z_TYPE_P(num) != IS_STRING || base == 10) {
115 		RETVAL_LONG(zval_get_long(num));
116 		return;
117 	}
118 
119 
120 	if (base == 0 || base == 2) {
121 		char *strval = Z_STRVAL_P(num);
122 		size_t strlen = Z_STRLEN_P(num);
123 
124 		while (isspace(*strval) && strlen) {
125 			strval++;
126 			strlen--;
127 		}
128 
129 		/* Length of 3+ covers "0b#" and "-0b" (which results in 0) */
130 		if (strlen > 2) {
131 			int offset = 0;
132 			if (strval[0] == '-' || strval[0] == '+') {
133 				offset = 1;
134 			}
135 
136 			if (strval[offset] == '0' && (strval[offset + 1] == 'b' || strval[offset + 1] == 'B')) {
137 				char *tmpval;
138 				strlen -= 2; /* Removing "0b" */
139 				tmpval = emalloc(strlen + 1);
140 
141 				/* Place the unary symbol at pos 0 if there was one */
142 				if (offset) {
143 					tmpval[0] = strval[0];
144 				}
145 
146 				/* Copy the data from after "0b" to the end of the buffer */
147 				memcpy(tmpval + offset, strval + offset + 2, strlen - offset);
148 				tmpval[strlen] = 0;
149 
150 				RETVAL_LONG(ZEND_STRTOL(tmpval, NULL, 2));
151 				efree(tmpval);
152 				return;
153 			}
154 		}
155 	}
156 
157 	RETVAL_LONG(ZEND_STRTOL(Z_STRVAL_P(num), NULL, base));
158 }
159 /* }}} */
160 
161 /* {{{ proto float floatval(mixed var)
162    Get the float value of a variable */
PHP_FUNCTION(floatval)163 PHP_FUNCTION(floatval)
164 {
165 	zval *num;
166 
167 	ZEND_PARSE_PARAMETERS_START(1, 1)
168 		Z_PARAM_ZVAL(num)
169 	ZEND_PARSE_PARAMETERS_END();
170 
171 	RETURN_DOUBLE(zval_get_double(num));
172 }
173 /* }}} */
174 
175 /* {{{ proto bool boolval(mixed var)
176    Get the boolean value of a variable */
PHP_FUNCTION(boolval)177 PHP_FUNCTION(boolval)
178 {
179 	zval *val;
180 
181 	ZEND_PARSE_PARAMETERS_START(1, 1)
182 		Z_PARAM_ZVAL(val)
183 	ZEND_PARSE_PARAMETERS_END();
184 
185 	RETURN_BOOL(zend_is_true(val));
186 }
187 /* }}} */
188 
189 /* {{{ proto string strval(mixed var)
190    Get the string value of a variable */
PHP_FUNCTION(strval)191 PHP_FUNCTION(strval)
192 {
193 	zval *num;
194 
195 	ZEND_PARSE_PARAMETERS_START(1, 1)
196 		Z_PARAM_ZVAL(num)
197 	ZEND_PARSE_PARAMETERS_END();
198 
199 	RETVAL_STR(zval_get_string(num));
200 }
201 /* }}} */
202 
php_is_type(INTERNAL_FUNCTION_PARAMETERS,int type)203 static inline void php_is_type(INTERNAL_FUNCTION_PARAMETERS, int type)
204 {
205 	zval *arg;
206 
207 	ZEND_PARSE_PARAMETERS_START(1, 1)
208 		Z_PARAM_ZVAL(arg)
209 	ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
210 
211 	if (Z_TYPE_P(arg) == type) {
212 		if (type == IS_RESOURCE) {
213 			const char *type_name = zend_rsrc_list_get_rsrc_type(Z_RES_P(arg));
214 			if (!type_name) {
215 				RETURN_FALSE;
216 			}
217 		}
218 		RETURN_TRUE;
219 	} else {
220 		RETURN_FALSE;
221 	}
222 }
223 
224 
225 /* {{{ proto bool is_null(mixed var)
226    Returns true if variable is null
227    Warning: This function is special-cased by zend_compile.c and so is usually bypassed */
PHP_FUNCTION(is_null)228 PHP_FUNCTION(is_null)
229 {
230 	php_is_type(INTERNAL_FUNCTION_PARAM_PASSTHRU, IS_NULL);
231 }
232 /* }}} */
233 
234 /* {{{ proto bool is_resource(mixed var)
235    Returns true if variable is a resource
236    Warning: This function is special-cased by zend_compile.c and so is usually bypassed */
PHP_FUNCTION(is_resource)237 PHP_FUNCTION(is_resource)
238 {
239 	php_is_type(INTERNAL_FUNCTION_PARAM_PASSTHRU, IS_RESOURCE);
240 }
241 /* }}} */
242 
243 /* {{{ proto bool is_bool(mixed var)
244    Returns true if variable is a boolean
245    Warning: This function is special-cased by zend_compile.c and so is usually bypassed */
PHP_FUNCTION(is_bool)246 PHP_FUNCTION(is_bool)
247 {
248 	zval *arg;
249 
250 	ZEND_PARSE_PARAMETERS_START(1, 1)
251 		Z_PARAM_ZVAL(arg)
252 	ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
253 
254 	RETURN_BOOL(Z_TYPE_P(arg) == IS_FALSE || Z_TYPE_P(arg) == IS_TRUE);
255 }
256 /* }}} */
257 
258 /* {{{ proto bool is_int(mixed var)
259    Returns true if variable is an integer
260    Warning: This function is special-cased by zend_compile.c and so is usually bypassed */
PHP_FUNCTION(is_int)261 PHP_FUNCTION(is_int)
262 {
263 	php_is_type(INTERNAL_FUNCTION_PARAM_PASSTHRU, IS_LONG);
264 }
265 /* }}} */
266 
267 /* {{{ proto bool is_float(mixed var)
268    Returns true if variable is float point
269    Warning: This function is special-cased by zend_compile.c and so is usually bypassed */
PHP_FUNCTION(is_float)270 PHP_FUNCTION(is_float)
271 {
272 	php_is_type(INTERNAL_FUNCTION_PARAM_PASSTHRU, IS_DOUBLE);
273 }
274 /* }}} */
275 
276 /* {{{ proto bool is_string(mixed var)
277    Returns true if variable is a string
278    Warning: This function is special-cased by zend_compile.c and so is usually bypassed */
PHP_FUNCTION(is_string)279 PHP_FUNCTION(is_string)
280 {
281 	php_is_type(INTERNAL_FUNCTION_PARAM_PASSTHRU, IS_STRING);
282 }
283 /* }}} */
284 
285 /* {{{ proto bool is_array(mixed var)
286    Returns true if variable is an array
287    Warning: This function is special-cased by zend_compile.c and so is usually bypassed */
PHP_FUNCTION(is_array)288 PHP_FUNCTION(is_array)
289 {
290 	php_is_type(INTERNAL_FUNCTION_PARAM_PASSTHRU, IS_ARRAY);
291 }
292 /* }}} */
293 
294 /* {{{ proto bool is_object(mixed var)
295    Returns true if variable is an object
296    Warning: This function is special-cased by zend_compile.c and so is usually bypassed */
PHP_FUNCTION(is_object)297 PHP_FUNCTION(is_object)
298 {
299 	php_is_type(INTERNAL_FUNCTION_PARAM_PASSTHRU, IS_OBJECT);
300 }
301 /* }}} */
302 
303 /* {{{ proto bool is_numeric(mixed value)
304    Returns true if value is a number or a numeric string */
PHP_FUNCTION(is_numeric)305 PHP_FUNCTION(is_numeric)
306 {
307 	zval *arg;
308 
309 	ZEND_PARSE_PARAMETERS_START(1, 1)
310 		Z_PARAM_ZVAL(arg)
311 	ZEND_PARSE_PARAMETERS_END();
312 
313 	switch (Z_TYPE_P(arg)) {
314 		case IS_LONG:
315 		case IS_DOUBLE:
316 			RETURN_TRUE;
317 			break;
318 
319 		case IS_STRING:
320 			if (is_numeric_string(Z_STRVAL_P(arg), Z_STRLEN_P(arg), NULL, NULL, 0)) {
321 				RETURN_TRUE;
322 			} else {
323 				RETURN_FALSE;
324 			}
325 			break;
326 
327 		default:
328 			RETURN_FALSE;
329 			break;
330 	}
331 }
332 /* }}} */
333 
334 /* {{{ proto bool is_scalar(mixed value)
335    Returns true if value is a scalar */
PHP_FUNCTION(is_scalar)336 PHP_FUNCTION(is_scalar)
337 {
338 	zval *arg;
339 
340 	ZEND_PARSE_PARAMETERS_START(1, 1)
341 		Z_PARAM_ZVAL(arg)
342 	ZEND_PARSE_PARAMETERS_END();
343 
344 	switch (Z_TYPE_P(arg)) {
345 		case IS_FALSE:
346 		case IS_TRUE:
347 		case IS_DOUBLE:
348 		case IS_LONG:
349 		case IS_STRING:
350 			RETURN_TRUE;
351 			break;
352 
353 		default:
354 			RETURN_FALSE;
355 			break;
356 	}
357 }
358 /* }}} */
359 
360 /* {{{ proto bool is_callable(mixed var [, bool syntax_only [, string &callable_name]])
361    Returns true if var is callable. */
PHP_FUNCTION(is_callable)362 PHP_FUNCTION(is_callable)
363 {
364 	zval *var, *callable_name = NULL;
365 	zend_string *name;
366 	char *error;
367 	zend_bool retval;
368 	zend_bool syntax_only = 0;
369 	int check_flags = 0;
370 
371 	ZEND_PARSE_PARAMETERS_START(1, 3)
372 		Z_PARAM_ZVAL(var)
373 		Z_PARAM_OPTIONAL
374 		Z_PARAM_BOOL(syntax_only)
375 		Z_PARAM_ZVAL(callable_name)
376 	ZEND_PARSE_PARAMETERS_END();
377 
378 	if (syntax_only) {
379 		check_flags |= IS_CALLABLE_CHECK_SYNTAX_ONLY;
380 	}
381 	if (ZEND_NUM_ARGS() > 2) {
382 		retval = zend_is_callable_ex(var, NULL, check_flags, &name, NULL, &error);
383 		ZEND_TRY_ASSIGN_REF_STR(callable_name, name);
384 	} else {
385 		retval = zend_is_callable_ex(var, NULL, check_flags, NULL, NULL, &error);
386 	}
387 	if (error) {
388 		/* ignore errors */
389 		efree(error);
390 	}
391 
392 	RETURN_BOOL(retval);
393 }
394 /* }}} */
395 
396 /* {{{ proto bool is_iterable(mixed var)
397    Returns true if var is iterable (array or instance of Traversable). */
PHP_FUNCTION(is_iterable)398 PHP_FUNCTION(is_iterable)
399 {
400 	zval *var;
401 
402 	ZEND_PARSE_PARAMETERS_START(1, 1)
403 		Z_PARAM_ZVAL(var)
404 	ZEND_PARSE_PARAMETERS_END();
405 
406 	RETURN_BOOL(zend_is_iterable(var));
407 }
408 /* }}} */
409 
410 /* {{{ proto bool is_countable(mixed var)
411    Returns true if var is countable (array or instance of Countable). */
PHP_FUNCTION(is_countable)412 PHP_FUNCTION(is_countable)
413 {
414 	zval *var;
415 
416 	ZEND_PARSE_PARAMETERS_START(1, 1)
417 		Z_PARAM_ZVAL(var)
418 	ZEND_PARSE_PARAMETERS_END();
419 
420 	RETURN_BOOL(zend_is_countable(var));
421 }
422 /* }}} */
423