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