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