PHP基础入门

大概是参加工作后的一个月吧开始学习PHP,最初只是草草地翻阅了一下手册,然后跟着后端的同学熟悉PHP框架开发,在ThinkPHP语法糖的诱惑下,一直没有深入PHP的基础知识(与其说是深入,不如说是了解)。PHP的函数十分繁杂,命名也比较混乱,然而项目中常规使用的函数:比如打印,判断,字符串,数组等函数和方法,应当是优先需要掌握的,因此重新整理有道云上面的笔记,进一步学习PHP。之后的目标是用PHP为我的小网站重新搭一遍(PS:自从用了Hexo,之前买的虚拟主机就一直撂在那里了...)

<!--more-->

1. 数据类型

变量类型是根据使用该变量的上下文所决定的,因此数据类型自动转换有时候会发生一些看似莫名其妙的事情。

1.1. 布尔值

当运算符,函数或者流程控制结构需要一个 boolean 参数时,将发生自动类型转换,下面数值都会转换为false:

  • 布尔值false
  • 整形数字0或浮点型数字0.0
  • 空字符串""或零字符串"0"
  • 空数组
  • 特殊类型NULL
  • 从空标记生成的 SimpleXML 对象 (表示从来没见过)

需要注意的是,不包含任何成员的对象现在也会被认为是true。

1.2. 数字

数字分为了整形和浮点型,使用除法运算符得到的是浮点数,将浮点数转换成整数有多种方法 不要将未知的分数强制转换为integer,因为会存在精度的丢失,比如

echo 0.1+0.7; //0.8
echo (int)((0.1+0.7)*10); // 7

也就是说,永远不要相信浮点数结果精确到了最后一位,这是在大多数语言中都存在的问题。

1.3. 字符串

与JS不同的是,PHP中的单引号与双引号所组成的字符串有明显区别

  • 在单引号字符串中的变量和特殊字符的转义序列将不会被替换
  • 而用双引号定义的字符串最重要的特征是变量会被解析
$a = 123;
echo "$a"; //123
echo '$a'; //$a

此外需要注意的是,PHP会将非数值的字符串的开始部分决定了它的值。如果该字符串以合法的数值开始,则使用该数值。否则其值为 0(零)。也就是说任意字符串都是可以转换成数字的(跟JS的isNaN判断有很大区别!)

2. 数组

PHP数组的键名是不限制必须为整形数字的,也就是说键名可以混用数字和字符串。 数组中多个元素都使用了同一个键名,则只使用了最后一个,之前的都会被覆盖。 数组中的键名会自动转换成整形数字(如果可行的话),在这种情况下,即使键名不完全相同,后面的值也会将前面的值覆盖。例外是如果键名是内容为浮点数的字符串,是不会发生这种类型转换的。

$a = array(
    1 => 'a',
    true => 'b',
    1.2 => 'c',
    '1' => 'd',
    '1.2' => 'e',
);
var_dump($a);
//结果
//  1 => string 'd' (length=1)
//  '1.2' => string 'e' (length=1)

访问数组元素时,如果给出方括号但没有指定键名,则取当前最大整数索引值,新的键名将是该值加上 1,相当于为数组新增了元素

$a = array(1,2)
$a[] = '3';
var_dump($a); // 1,2,3

可以使用foreach方法快速遍历数组

foreach ($array as $key => $value) {
    echo $value."<br/>";
}

由于 foreach 依赖内部数组指针,在循环中修改其值将可能导致意外的行为。

3. 变量

PHP中使用($)符号加变量名来定义一个变量,变量名区分大小写。

3.1. 变量解析与赋值

PHP可以在双引号字符串中插入变量并正确解析,变量解析大概是为了方便在进行某些情况下(比如sql语句中)减少字符串的拼接,主要有有两种规则:

  • 简单规则,即在一个双引号字符串中嵌入一个变量,一个 array 的值,或一个 object 的属性。
    • 当PHP解析器遇到一个($)符号时,就会去组合尽量多的标识以形成一个合法的变量名;
    • 同理,HP解析器遇见数组索引方括号([])和对象属性索引(->)也会去组合标识并找到对应的变量。
  • 复杂规则,只需简单地像在 string 以外的地方那样写出表达式,然后用花括号 { 和 } 把它括起来,并嵌入到双引号字符串中即可,需要注意的是($)符号必须与({)符号紧挨着,否则无法被解析。

变量默认总是传值赋值(包括数组,这里也是与JS完全不同的地方)。那也就是说,当将一个表达式的值赋予一个变量时,整个原始表达式的值被赋值到目标变量。 如果需要使用引用赋值,则需要将&符号加到将要赋值的变量前

$a = 1;
$b = $a;
$c = &$a;

$b = 100;
echo $a; //1

$c = 100;
echo $a; // 100

3.2. 变量作用域

变量的作用域主要分为了全局变量和局部变量:

  • 不在任何函数内的变量拥有全局作用域。
  • 在用户自定义函数中,一个局部函数范围将被引入。任何用于函数内部的变量按缺省情况将被限制在局部函数范围内。

尽管被称为全局变量,PHP 中全局变量在函数中使用时必须声明为 global才能够使用,否则就会报”变量未定义“的错误。

$a = 1;
function foo(){
    global $a;
    echo $a;
}

此外PHP还存在静态变量,静态变量只在局部函数作用域中存在,但是当该函数调用结束之后,该变量的值并不会丢失(作用于C语言中的static类似),使用static定义静态变量。

function foo(){
    static $a = 0;
    $a++;
    echo $a;
}
foo(); //1
foo(); //2

3.3. 超全局变量

PHP定义的一些变量,用来处理接收到的表单数据等...

3.4. 常量

可以使用define()函数或者const关键字来定义一个其值不可改变的常量

  • 常量不需要$符号
define('TEST',1);
const TEST2 = 10;
echo TEST; //1
echo TEST2; //10

需要注意的是使用const定义常量只能在全局作用域下进行,在函数内部无法使用这种方式定义常量,而使用define则没有这种限制。 此外,使用define在函数内部定义的常量也可以在全局作用域下访问到。

4. 流程控制

在PHP中的流程控制语句中,还可以使用冒号代替花括号,使用elseif和endif这些缩写。

$a = 1;
$b = 2;
//1
if ($a > $b):
    echo 1;
elseif($a == $b):
    echo 2;
else:
    echo 3;
endif;
//2
if ($a > $b){
    echo 1;
}else if($a == $b){
    echo 2;
}else {
    echo 3;
}

甚至第二种写法中的else if也可以写作elseif的形式,然而我更习惯分开带大括号的习惯,所以,这里就大概就是看个人喜好了吧。

5. 函数

5.1. 函数作用域

任何有效的PHP代码都可以出现在函数的内部,甚至包括其他函数和类的定义。 此外PHP中的所有函数和类都具有全局作用域,也就是可以在全局作用域中调用一个在函数作用域中定义的函数,前提是其父函数已经被调用(该函数已经执行定义流程才可以)

function foo(){
    echo 'In foo';

    function foo2(){
        echo 'In foo2';
    }
}
foo(); //必须调用父函数进行定义之后
foo2(); //可直接调用

5.2. 函数参数与返回值

参数默认是通过按值传递,可以在函数定义的时候指定为按引用传递,只需要在参数前加上&符号即可,此外,如果只是需要某次函数调用的时候按引用传递,也可以在实参前加上&。

function changeMax(&$a,&$b){
    if ($a > $b){
        $t = $a;
        $a = $b;
        $b = $t;
    }
}

$a = 10;
$b = 1;
changeMax($a,$b);
echo $a.','.$b; //1,10

跟C++一样,可以为函数设置默认参数,同时任何默认参数必须放在任何非默认参数的右侧

function foo($a,$b=1){}

如果没有指定return,则默认返回值为NULL。

6. 类与对象

对象的属性可以临时增加,但是仅限于该对象访问,类实例化的其他对象并没有该临时属性。 对象之间的赋值时按引用传递,改变一个对象变量会影响到另一个变量所指向的同一个对象。但是当将对象显示的置为null时,按值传递的对象变量不会被删除,而按显式按引用传递的对象变量会同时被删除。

7. 常用函数

PHP中的函数非常多,也非常强大,只是各种花式命名让人目不暇接,心中感慨还是面向对象好哇(关键我还是个驼峰命名爱好者,样式表不算)!最后整理了一些常用的PHP函数。

7.1. 数字

intval(): 将参数转换为整形数字,如果为浮点数,只保留浮点数的整数部分 is_numeric():检测参数是否为数字,返回布尔值 is_nan():检测参数是否为NaN

PHP会将非数值的 string 当成 0,也就是说使用上述两个函数来检测字符串是否能够转换成数字是行不通的(这里跟JS的差别很大)

$a = 'xxx';
echo intval($a); //0

ceil():向上取整 floor():向下取整

max():参数为一个数组或多个数字,返回其中最大值 min():同上,返回参数中的最小值

mt_rand(start,end):返回某个范围内的随机数

7.2. 数组

in_array($v,$arr):检查一个元素是否在数组中 array_slice($arr,start,end):截取指定索引值范围的子数组

array_push($arr,$v1,$v2...):将一个或多个元素放在数组最后 array_pop($arr):删除数组中最后一个元素

array_unshift($arr,$v1,$v2...):向数组头部插入元素 array_shift($arr):删除数组中第一个元素

sort($arr):从小到大进行数组排序 rsort($arr):从大到小排序 shuffle($arr):将数组打乱

array_merge($arr1,$arr2):合并两个数组 array_unique($arr):移除数组中重复的元素

implode($arr,$char):把数组按指定分隔符拼接成字符串 //join()

7.3. 字符串

strlen():返回字符串的长度 trim($str):去除字符串左右空格 strtolower($str):将字符串全部小写 strtoupper($str):将字符串全部大写

strpos($str,$c,[int]):查询指定子字符串在字符串中出现的位置,第三个参数指定起始查找位置 substr($str,$start,$length);截取指定长度的字符串 str_replace($search,$replace,$str):替换字符串中的某些字符

str_split($str,$len):把字符串按len长度进行分割并返回数组 explode($search,$str):把字符串按指定字符进行分割并返回数组

7.4. 编码

json_encode():对数组进行JSON编码, json_decode():对JSON格式的字符串进行编码

urlencode():本函数将字符串进行 URL 编码 urldecode():本函数将 URL 编码后字符串还原成未编码的样子

可以使用这两个函数来解决json_encode后默认编码为unicode的问题,为了解决深层嵌套的问题单独写了一个函数

function json_encode_fixed($arr){
    function json_encode_fixed_foo(&$arr){
        foreach ( $arr as $key => $value ) {
            if (is_array($value)){
                $arr[$key] = json_encode_fixed_foo($value);
            }else {
                $arr[$key] = urlencode ( $value );
            }
        }
        return $arr;
    }
json_encode_fixed_foo($arr);
return urldecode(json_encode($arr));

} ```

7.5. 日期

time():返回时间戳 date('Y-m-d h:i:s',time()):根据第一个字符串参数的格式打印出对应的日期,第二个参数为当前时间戳 strtotime():将时间字符串转换成时间戳

2018年五月面试发现的一些问题 BFC及其应用