PHP 其实很早之前就学过,但时间一长没有用,基本上是忘了。所以最近是重新捡起来。 PHP 很语法还是很缝合的,光看它面向过程的语法像 C ,但面向对象像 C++ 和 Java 的杂交,而且 PHP 虽然兼容,但如果尽量用上新特性的话,都觉得是两门语言。我并不打算学过去 PHP 5 那种语法,当初学得恶心,最新的 PHP 语法其实好很多。

变量与常量定义

变量

PHP 的变量名都以 $ 开头,槽点挺多的, PHP 程序员是多想要钱啊……咳咳,除开 $ ,变量名其实与一般语言命名一样。

<? php
$greeting = "Hello, World!";
$_greeting = "Hello, World!";
$greeting_1 = "Hello, World!";
# $1greeting = "Hello, World!"; 错误
# $greeting-1 = "Hello, World!"; 错误
?>

PHP 作为一门若类型的动态弱类型语言,声明变量和使用都十分灵活。

<?php
$greeting = "你好, PHP!";
$var_name = "greeting";
echo $$var_name; // 等同于 echo $greeting;
?>

因为 $varName 的变量值是 greeting ,所以当我们调用 $$varName 时, $varName 被替换成 greeting ,因此实际上引用的是 $greeting ,由于 $varName 的值可以动态设置,所以也就可以实现了一个可变变量。

常量

PHP 的常量使用 define 方法定义,也可以使用 const 关键字定义,不过 const 一般在类中使用居多,但在文件中使用也是可以的。

<?php
define("HELLO", "HELLO");
const WORLD = "WORLD";
echo HELLO." ".WORLD;
?>

基本数据类型

主要是数字、字符串、布尔这三类。查看数据类型我们可以使用 var_dump 方法。

数字

数字分为整型与浮点型。

<?php
$time = 2022;
var_dump($time); // int(2022)
$f = 2.2;
var_dump($f); // float(2.2)
?>

不过需要注意的是, 1 / 2 结果为浮点数,而不是整型。

<?php
echo var_dump(1 / 2); // float(0.5)
?>

字符串

PHP 字符串使用单引号和双引号皆可,但二者在功能上稍有区别。

<?php
echo '\'\n';
echo "\n";
?>

单引号不发生转义,除了 \' 。双引号可以,同时也可以类似模板字符串使用变量。

<?php
$name = "Jack";
$hello = "Hello World, $name\n";
echo $hello;
$name = "Mike";
echo $hello;
echo "Hello World, {$name}\n";
echo "Hello World, ${name}\n";
# Output:
# Hello World, Jack
# Hello World, Jack
# Hello World, Jack
# Hello World, Jack
?>

多行字符串使用 <<<'END' ... END<<<END ... END ,区别也在于一个转义一个不转义。

<?php
// Since PHP 5.3, nowdocs can be used for uninterpolated multi-liners
$nowdoc = <<<'END'
Multi line
string
END;

// Heredocs will do string interpolation
$heredoc = <<<END
Multi line
$sgl_quotes
END;
?>

布尔

PHP 的布尔类型数值如常规一样,是 truefalse ,但两个值大小写不敏感。

<?php
$boolean = true;  // or TRUE or True
$boolean = FALSE; // or false or False
?>

类型判断与类型转换

虽然 var_dump 可以判断类型,但有时候我们想要更直接的方法去判断,因此 PHP 提供了 is_stringis_int/is_integeris_float/is_doubleis_bool 等方法。

PHP 的类型转换形式上与 C 语言还是很相似的。

<?php
$str = "123";
$int = 2020;
$float = 99.0;
$bool = false;

var_dump((int) $str);
var_dump((bool) $str);
var_dump((string) $str);
var_dump((bool) $str);
var_dump((int) $float);
var_dump((string) $float);
var_dump((string) $bool);
var_dump((int) $bool);
?>

数组

PHP 数组比较早的时候只能用 array 方法,后面才有 [] 语法,两种创建方式实际上是类似的。

PHP 数组与 lua 的 table 类似,揉捏了列表和字典的结构,但是从 0 开始。

<?php
$nums = [2, 4, 8, 16, 32];
$nums_old = array(2, 4, 8, 16, 32);
echo var_dump($nums);
echo var_dump($nums_old);
?>

PHP 数组也可以当作字典使用。

<?php
$book = ['name' => '不能承受的生命之轻', 'author' => '米兰昆德拉'];
$book_old = array('name' => '不能承受的生命之轻', 'author' => '米兰昆德拉');
echo var_dump($book);
echo var_dump($book_old);
?>

也可以混合使用。

<?php
$game = ['明日方舟', 'company' => '鹰角网络'];
$game_old = array('明日方舟', 'company' => '鹰角网络');
echo var_dump($game);
echo var_dump($game_old);
?>

没有定义索引的就自动使用数字进行索引了。

当然,虽然我们可以写代码进行增删,但如果语言本身提供了就更加方便了。在 PHP 中,我们可以使用 array_push 进行添加,使用 unset 来取消数组中的某一个值。

<?php
$a = [1, 2, 3];
array_push($a, 5);
print_r($a);
unset($a[1]);
print_r($a);
?>

unset 也可以用来取消任何一个变量,如果我们想要删除整个数组,我们可以直接 unset($a)

PHP 也允许我们直接用索引的方式添加。

<?php
$a = [1, 2, 3];
$a[3] = 5;
print_r($a);
unset($a[1]);
print_r($a);
?>

但这里有一个问题,就是当我们删了一个值之后,数字索引就乱了, PHP 为我们提供了一个方法来重排索引, array_values

<?php
$a = [1, 2, 3];
$a[3] = 5;
print_r($a);
unset($a[1]);
$a = array_values($a);
print_r($a);
?>

如果我们想知道数组大小呢?我们可以通过 count 函数获得。

<?php
$a = [1, 2, 3];
echo count($a);
?>

你可以看到上面的代码我们用了两种不同的方式打印数组, var_dumpprint_rvar_dump 会详细展示类型信息,而 print_r 则会吐出更精简的数组结构,区别仅仅在此。

PHP 控制结构

PHP 的控制结构与 C 语言大致相近,除了 foreach

分支结构

if

<?php
if (true) {
    print 'I get printed';
}

if (false) {
    print 'I don\'t';
} else {
    print 'I get printed';
}

if (false) {
    print 'Does not get printed';
} elseif (true) {
    print 'Does';
}

if (false) {
    print 'Does not get printed';
} else if (true) {
    print 'Does';
}
?>

还有一种模板结构。

<?php if ($x): ?>
This is displayed if the test is truthy.
<?php else: ?>
This is displayed otherwise.
<?php endif; ?>

switch

<?php
$x = 0;
switch ($x) {
    case '0':
        print 'Switch does type coercion';
        break; // You must include a break, or you will fall through
               // to cases 'two' and 'three'
    case 'two':
    case 'three':
        // Do something if $variable is either 'two' or 'three'
        break;
    default:
        // Do something by default
}
?>

while

<?php
$i = 0;
while ($i < 5) {
    echo $i++;
} // Prints "01234"

echo "\n";

$i = 0;
do {
    echo $i++;
} while ($i < 5); // Prints "01234"
?>

foreach

PHP 的 foreach 主要是用于迭代的。

<?php
foreach($data as $key => $val) {
    // ...
}
?>

这里的 $data 是需要迭代的对象, $key 是键名, $val 是键值。如果只想要值的话可以不要 $key

<?php
foreach($data as $val) {
    // ...
}
?>
<?php
$wheels = ['bicycle' => 2, 'car' => 4];

// Foreach loops can iterate over arrays
foreach ($wheels as $wheel_count) {
    echo $wheel_count;
} // Prints "24"

echo "\n";

// You can iterate over the keys as well as the values
foreach ($wheels as $vehicle => $wheel_count) {
    echo "A $vehicle has $wheel_count wheels";
}

echo "\n";
?>

for

PHP 的 for 与 C 大致一样。

<?php
$i = 0;
for ($i = 0; $i < 5; $i++) {
    if ($i === 3) {
        continue; // Skip this iteration of the loop
    }
    echo $i;
} // Prints "0124"
?>

运算符

除了正常的加减乘除之外, PHP 还引入了求幂符号 **

PHP 还有自增运算符 --++

比较运算符的情况类似于 JavaScript ,基本上就是多了 <><=> 。前者等于 != ,后者情况比较特殊,被称做结合比较运算符。

<?php
$a = 100;
$b = 1000;

echo $a <=> $a; // 0 since they are equal
echo $a <=> $b; // -1 since $a < $b
echo $b <=> $a; // 1 since $b > $a
?>

逻辑运算符与 C 语言一致。

特别提一点,字符串连接使用 . 而不能使用 +

函数

自定义函数

<?php

/**
 * 计算两数相加之和
 * @param $a
 * @param $b
 * @return mixed
 */
function add($a, $b) {
    $sum = $a + $b;
    return $sum;
}
?>

从 PHP 7 开始允许声明数值类型。

<?php
/**
 * 计算两数相加之和
 * @param int $a
 * @param int $b
 * @return int
 */
function add(int $a, int $b): int {
    $sum = $a + $b;
    return $sum;
}
?>

这样,任何非 int 类型的参数都无法传入。

函数参数默认以值传递方式进行传递,无论是基本类型还是其他的。想要引用传递则使用 & 符号。

<?php
$a = [1, 2, 3];
function test(array $k) {
    $k[1] = 1;
}
test($a);
print_r($a); // 没变
function test_1(array &$k) {
    $k[1] = 1;
}
test_1($a);
print_r($a); // 变了
?>

匿名函数

<?php
$add = function(int $a, int $b): int {
    return $a + $b;
};
$sum = $add(1, 2);
echo $sum . PHP_EOL;
?>

可变参数与默认参数

可变参列表使用 ... 定义。

<?php
function call_user_func ($function, ...$parameter) {
    print_r($parameter);
}
?>

默认参数需要放到最后。

<?php
function add($x, $y = 1) { // $y is optional and defaults to 1
    $result = $x + $y;
    return $result;
}
?>

还有一种完全放弃治疗的获取参数方式。

<?php
// You can get all the parameters passed to a function
function parameters() {
    $numargs = func_num_args();
    if ($numargs > 0) {
        echo func_get_arg(0) . ' | ';
    }
    $args_array = func_get_args();
    foreach ($args_array as $key => $arg) {
        echo $key . ' - ' . $arg . ' | ';
    }
}

parameters('Hello', 'World'); // Hello | 0 - Hello | 1 - World |
?>

可变函数

以匿名函数的方式定义的变量也被视作函数变量,由于是变量,所以就可以被重新定义。这种在运行时动态设置函数类型值给变量的功能,在 PHP 中称之为可变函数。

<?php
/**
 * 通过匿名函数定义两数相加函数 add
 * @param int $a
 * @param int $b
 * @return int
 */
$add = function (int $a, int $b = 2): int {
    return $a + $b;
};

/**
 * 两数相乘函数 multi
 * @param int $a
 * @param int $b
 * @return int
 */
$multi = function (int $a, int $b): int {
    return $a * $b;
};

// 调用匿名函数
$n1 = 1;
$n2 = 3;
$sum = $add($n1, $n2);
echo "$n1 + $n2 = $sum" . PHP_EOL;
// 将 multi 赋值给 $add
$add = $multi;
$product = $add($n1, $n2);
echo "$n1 x $n2 = $product" . PHP_EOL;
?>

函数作用域

PHP 的函数作用域是隔得非常清楚的,如果不声明,函数是无法使用父作用域的。

<?php
$n1 = 1;
$n2 = 3;

function t() {
    global $n1;
    return function () use ($n1) {
        return $n1;
    };
}

// 计算两数相加
$add = function () use ($n1, $n2) {
    return $n1 + $n2;
};

// 计算两数相乘
$multi = function () use ($n1, $n2){
    return $n1 * $n2;
};

// 调用匿名函数
$sum = $add();
echo "$n1 + $n2 = $sum" . PHP_EOL;
$product = $multi();
echo "$n1 x $n2 = $product" . PHP_EOL;
?>

对于匿名函数,可以使用 use 使用父作用域关键字,同样也可以使用 global 定义全局作用域可访问值。除此之外, PHP 还提供了 $GLOBALS 数组,数组内就是全部的全局变量。

小结

PHP 是个多范式编程语言,面向过程编程只是其最基本的编程形式。相对其他语言来说, PHP 是个自由度非常大的语言,同时也对代码质量管理提出了挑战。关于 PHP 的 OOP ,以后有时间再谈吧!