标题:【PHP小课堂】学习PHP中的变量处理相关操作
学习PHP中的变量处理相关操作
今天要学习的内容是和 PHP 中的变量处理相关的一些操作函数,很多都是在之前的文章中已经学习过的内容,所以也比较简单好理解。当然,这个简单和好理解也是建立在我们之前已经学习或接触过相关的内容的前提下才能感受到的,比如说我们变量的自动转换之类的知识。大家在学习的过程中,如果有疑问,可以翻阅之前的文章或视频,或者自己查阅相关的资料。
类型转换
首先就是类型的转换,也可以说是类型的强制转换这块的知识。对于 PHP 来说,如果不是特别的需求,往往并不需要我们过于地关心类型的问题,这也是动态语言和静态语言最大的区别之一。当然,现代语言之间的相互融合以及 PHP 未来的发展,都是需要静态能力的支持的,毕竟固定的类型能够为程序执行效率带来许多地好处。
$a = 1;
$b = '2.2';
$c = true;
// 类型转换
var_dump(boolval($a));
var_dump(doubleval($b));
var_dump(floatval($b));
var_dump(intval($b));
var_dump(strval($c));
// bool(true)
// float(2.2)
// float(2.2)
// int(2)
// string(1) "1"
xxxval() 这几个函数可以说是我最早接触到的 PHP 中类型转换相关的函数。不过现在已经用得非常少了,为什么呢?因为和 Java 之类的静态语言一样,PHP 也支持直接地进行类型转换了,而且是早就已经支持了。
var_dump((bool)$a);
var_dump((double)$b);
var_dump((float)$b);
var_dump((int)$b);
var_dump((string)$c);
var_dump((array)$c);
var_dump((object)$c);
// bool(true)
// float(2.2)
// float(2.2)
// int(2)
// string(1) "1"
// array(1) {
// [0]=>
// bool(true)
// }
// object(stdClass)#1 (1) {
// ["scalar"]=>
// bool(true)
// }
这种形式和 Java 它们的 强制转换 是不是就非常像了,而且也更加地方便好用。上面的 xxxval() 形式的内容转换只能对标量类型操作,而这种形式的还可以将变量转换为数组和对象。在转换为对象之后,会生成一个 stdClass 类型的对象,这个变量也会变成这个对象当中的 scalar 属性。这个 scalar 就是标量的意思。
设置类型及获取变量类型信息
除了上面的两种方式之外,我们还可以通过另外一个函数来转换变量的类型。
$d = 1;
settype($d, 'array');
var_dump($d);
// array(1) {
// [0]=>
// int(1)
// }
settype() 函数的第一个参数是引用类型的变量,也就是说,转换之后这个变量类型就会变成第二个参数所指定的类型。在这里我们再插入一段测试,那就是针对数组的转换除了 settype() 和 强制转换 之外,还有一种形式。
$d = 1;
var_dump(array($d));
// array(1) {
// [0]=>
// int(1)
// }
既然有 settype() ,那是不是也有一个对应的 gettype() 呢?没错,你太聪明了,gettype() 是用于获取变量类型的。
var_dump(gettype($d)); // string(7) "integer"
// var_dump(get_debug_type($d)); // PHP8 string(3) "int"
注释中的代码是在 PHP8 中新增加的一个函数。可以看出,gettype() 返回的是标准的类型名称,也就是类型的全称。而 get_debug_type() 返回的是我们常用的类型名称。这个 int 就是我们常用的类型名称,而它的标准名称则是 integer 。get_debug_type() 我没有测试,当前也没有 PHP8 环境,大家如果有 PHP8 的开发环境可以自行测试一下。
判断变量是否存在及值的情况
我们先来看看判断一个变量是否存在。
var_dump(isset($e)); // bool(false)
$ee = '';
var_dump(isset($ee)); // bool(true)
unset($ee);
var_dump(isset($ee)); // bool(false)
$ee = NULL;
var_dump(isset($ee)); // bool(false)
相信这个 isset() 函数也是大家常用的函数了。它用于判断给定的变量是否存在,也就是是否定义。当然,NULL 值也会直接视为变量不存在。不过这个函数更多的会用在我们处理数组数据中,比如接收到的 $_POST 里面是否有指定的参数存在。
这个函数就不多说了,它和我们下面要讲的 empty() 之间的区别还是很好理解的。我们今天主要看一下 empty() 和直接的 if 之间是什么关系。
empty() 与直接 if
$e;
if(empty($e)){
echo 'empty';
}
if(!$e){
echo 'empty';
}
// empty
// empty
貌似直接的 if 取反的判断和 empty() 的区别不大。事实上也确实如此,如果你的很多代码中使用了 empty() 其实都可以直接使用 if 取反这种形式来代替。不过,它们之间在定义上其实还是略有区别的。
if 条件的判断是将括号里面的内容转换成一个布尔表达式。如果没有判断操作符,比如 == 、> 、< 这些的话,那就是直接将这个变量进行隐式的布尔转换。还记得布尔值的转换规则吗?以下内容将会转换成布尔值中的 FALSE :
布尔值 false 本身
整型值 0(零)及 -0 (零)
浮点型值 0.0(零)-0.0(零)
空字符串,以及字符串 "0"
不包括任何元素的数组
特殊类型 NULL(包括尚未赋值的变量)
从空标记生成的 SimpleXML 对象
接下来我们再看一看 empty() 的判断条件:
"" (空字符串)
0 (作为整数的0)
0.0 (作为浮点数的0)
"0" (作为字符串的0)
null
false
array() (一个空数组)
$var; (一个声明了,但是没有值的变量)
看看它们俩,其实没什么区别。对于我来说,现在更喜欢直接使用 if 取反的方式来代替 empty() 函数的使用,因为我感觉这样的写法更简洁明了。当然,这里也不是说哪种方式更好,只是个人感觉而已,具体要使用哪种,还是仁者见仁了。注意,对于不存在的变量,empty 没有报错信息,而 if 会有 E_NOTICE 级别的报错。
类型判断函数
在类型判断函数中,简单的那些 is_int()、is_array()、is_bool() 这些的就不多说了,我们来看一些平常比较少见的。
$f = function(){};
var_dump(is_callable($f)); // emptyemptybool(true)
var_dump(is_countable($d)); // bool(false)
var_dump(is_countable((array)$d)); // bool(true)
class A implements Countable {
public function count(){
return 1;
}
}
var_dump(is_countable(new A)); // bool(true)
注意看清楚这段代码哦,是有两个判断函数的。一个是 is_callable() 判断函数是否是一个匿名回调函数。别一个是 is_countable() ,用于判断给定的变量是否是可计数的。判断匿名函数的不用多说了,主要来看一下 is_countable() ,数组、实现了 Countable 接口的对象它都会返回 ture 。也就是说,只要是可以计数的类型,都是它的判断范围。
var_dump(is_iterable($d)); // bool(false)
var_dump(is_iterable((array)$d)); // bool(true)
var_dump(is_iterable(new A)); // bool(false)
var_dump(is_iterable((function(){yield 1;})())); // bool(true)
上面是可计数的变量,这里的 is_iterable() 判断的则是可迭代的对象。关于迭代器相关的内容之前的文章中也讲解过了,在这里,一是数组,二是实现了迭代器的对象,三是生成器,它们都是可迭代的类型,这三个是 is_iterable() 返回 true 的条件。
var_dump(is_scalar($a)); // bool(true)
var_dump(is_scalar((array)$a)); // bool(false)
最后是 is_scalar() 这个函数,它的作用是判断给定的变量是否是标量类型的。前面也提到过这个标量类型,可能有的同学还不太清楚这个名词的意思。其实就是除了对象、数组之外那些默认的固定类型,比如 int 、float 这些就都是标量类型。
获取所有当前环境下的变量信息
var_dump(get_defined_vars());
// array(11) {
// ["_GET"]=>
// array(0) {
// }
// …………………………
// …………………………
// ["argv"]=>
// array(1) {
// [0]=>
// string(108) "/Users/zhangyue/MyDoc/博客文章/dev-blog/php/2021/05/source/5.学习PHP中的变量处理相关操作.php"
// }
// ["argc"]=>
// int(1)
// ["_SERVER"]=>
// array(39) {
// ["VSCODE_NODE_CACHED_DATA_DIR"]=>
// string(100) "/Users/zhangyue/Library/Application Support/Code/CachedData/e713fe9b05fc24facbec8f34fb1017133858842b"
// ["SHELL"]=>
// string(8) "/bin/zsh"
// …………………………
// …………………………
// }
// ["a"]=>
// int(1)
// ["b"]=>
// string(3) "2.2"
// ["c"]=>
// bool(true)
// ["d"]=>
// int(1)
// }
get_defined_vars() 函数会打印当前 PHP 运行环境下的所有变量信息。这里不仅的系统默认自带的那些变量,还有会我们自定义的变量放在最下方。这个和我们之前讲过的 get_defined_functions() 函数是类似的,它输出的是全部的函数信息,忘记了这部分内容的小伙伴可以稳步 PHP中的函数相关处理方法学习https://mp.weixin.qq.com/s/Qx5dJRuyPDRmpPxs3gKiDg 去复习一下哦。
变量引用信息查看
如果说我们要查看一个变量的引用信息,要怎么办呢?很多小伙伴就会说到使用 xdebug 呀,我们之前的文章 PHP的引用计数是什么意思?https://mp.weixin.qq.com/s/WeZL4EzptDPQnkrFXxisgQ 中也讲解过。不过今天我们要学习的这个函数更方便,而且不需要安装别的扩展就能直接看到。
debug_zval_dump($b); // string(3) "2.2" refcount(1)
$b .= ' + 3.3';
$bb = $b;
debug_zval_dump($bb); // string(9) "2.2 + 3.3" refcount(3)
debug_zval_dump($a); // int(1)
$aa = &$a;
debug_zval_dump($a); // int(1)
debug_zval_dump($aa); // int(1)
debug_zval_dump() 这个函数可以查看非标量类型变量的引用计数情况。从测试代码中可以看出,如果是标量类型,是看不到变量的引用计数情况的。当然,这个函数的功能比较简单,没有 xdebug 强大,不过如果有相关的调试需求,也是可以直接拿来使用的。
句柄信息查看
句柄变量是一种很特殊的变量类型,但它也是非常重要的一种类型之一。句柄就是打开的某一种资源的资源符,最常见的就是对文件的操作,fopen() 获得的就是这样一个文件的资源符。另外还有 curl 以及早期的 mysql_connect() 等都是这样的句柄。虽说同样都是句柄这个类型,但它们还是不同的,毕竟操作的资源不是同一个东西,那么我们可以获取到某个句柄是什么类型的资源信息吗?
$curl = curl_init();;
var_dump(get_resource_type($curl)); // string(4) "curl"
$fp = fopen("./4.一起学习PHP中的反射(四).php", "w");
var_dump(get_resource_type($fp)); // string(6) "stream"
// var_dump(get_resource_id($curl)); // PHP8
get_resource_type() 函数就是获取句柄资源类型的一个函数。在测试代码中,我们分别定义了一个 curl 和一个文件操作的句柄,通过 get_resource_type() 函数可以看出它们一个是 curl 类型,一个是 stream 类型。文件都是流式操作的,所以 stream 类型的资源对应的正是文件操作的句柄。
另外还有一个 get_resource_id() 可以获得句柄的资源 ID ,不过这个函数是 PHP8 中才有的,有对应环境的同学可以自己测试一下哦。
总结
PHP 中的变量处理相关的函数就是这些了,内容非常简单,不过就像文章开头所说的,简单也是相对于我们之前已经掌握了很多对应的知识来说的。如果你对变量的隐式类型转换不清楚的话,那么强转的时候某些结果也不会是你所预想的那样。同理,empty() 和 if 条件的判断也是类似的,需要有这方面的知识理解才不会在日常开发中出现一些隐式转换所带来的问题。不管怎么说,实践是很重要,但一些基础概念的熟记也是非常重要的内容,学习就是这样,理论+实践的不断尝试才能让我们掌握的更加牢固,多动手多背吧,没坏处。
测试代码:
参考文档: