PHP

Table of Contents

1. PHP 简介

PHP 是一种流行的编程语言。

1.1. Redhat 中安装 PHP

1.1.1. 从仓库中安装 php

如果 Redhat 官方仓库中找不到打好包的 php,可以使用“Remi's RPM repository”中的 php,如:

$ sudo yum install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm # 启用EPEL
$ sudo yum install -y http://rpms.remirepo.net/enterprise/remi-release-7.rpm  # 启用Remi's RPM repository
$ sudo yum install php73          # 安装PHP
$ sudo yum install php73-php-fpm  # 安装PHP FastCGI Process Manager

下面是安装 mysql 扩展:

sudo yum install php73-php-pdo
sudo yum install php73-php-mysqlnd

安装完成后,可以使用下面命令启动 php-fpm:

$ sudo systemctl start php73-php-fpm.service

1.1.2. 从源码安装 php

下载源码包后,主要安装步骤如下:

$ tar zxf php-x.x.x
$ cd ../php-x.x.x
$ ./configure --enable-fpm --with-mysqli --with-curl  # 其它模块可以酌情增加
$ make
$ sudo make install

参考:
http://php.net/manual/en/install.unix.nginx.php
https://blog.csdn.net/xiao_zhui/article/details/72556781

1.2. 安装 PHP 扩展(pear vs. pecl)

扩展 PHP 有两种方法:
1、用纯粹的 PHP 代码写函数和类,Pear 就是这样一个项目,可以认为它是 PHP 的上层扩展,其主页是 https://pear.php.net ,使用命令行工具 pear 可以安装这类扩展;
2、用 C 或者 C++编写“外部模块”加载至 PHP 中,Pecl 是这样一个项目,可以认为它是 PHP 底层扩展,其主页是 https://pecl.php.net ,使用命令行工具 pecl 可以安装这类扩展。

参考:
pear help
pecl help

1.2.1. 实例:安装 redis 扩展

下面是安装 redis 扩展的例子:

$ sudo pecl install redis

上面命令执行成功后,你会发现配置文件 php.ini(它的具体位置可以通过 php --ini 查看)中会增加下面内容:

extension="redis.so"

1.3. 查看已安装的模块

执行命令 php -m 可以查看已经安装的模块(包括内置模块和外部模块),如:

$ php -m
[PHP Modules]
bcmath
Core
ctype
curl
date
dom
filter
ftp
gd
gettext
hash
iconv
intl
json
libxml
mbstring
mcrypt
mysqli
mysqlnd
openssl
pcntl
pcre
PDO
pdo_mysql
pdo_sqlite
Phar
posix
Reflection
session
shmop
SimpleXML
soap
sockets
SPL
sqlite3
standard
sysvsem
tokenizer
xml
xmlreader
xmlrpc
xmlwriter
xsl
zip
zlib

[Zend Modules]

执行命令 php --ini 可查看 php.ini 文件的位置:

$ php --ini
Configuration File (php.ini) Path: /usr/local/php/etc
Loaded Configuration File:         /usr/local/php/etc/php.ini
Scan for additional .ini files in: /usr/local/php/conf.d
Additional .ini files parsed:      (none)

1.4. Composer

Composer is a tool for dependency management in PHP. It allows you to declare the libraries your project depends on and it will manage (install/update) them for you. PHP 的 Composer 类似于 node 的 npm。

工程根目录中的文件 composer.json 用于描述当前工程的依赖。下面命令会安装 composer.json 中声明的依赖到工程根目录下的 vendor 子目录中:

$ composer install

2. PHP 基本语法

2.1. Hello World(PHP Tag 介绍)

下面是 PHP 版本的 Hello World:

<!DOCTYPE html>
<html>
 <head>
 <title>PHP Test</title>
 </head>
 <body>
 <?php
   echo '<p>Hello World</p>';
 ?>
 </body>
</html>

php 仅处理 php tag 中的内容,php tag 以 <?php 开始, ?> 结束。

<?php echo '<p>Hello World</p>'; ?>

其中,开始标记中的 PHP 关键字也可以省略,即上行代码等同于:

<? echo '<p>Hello World</p>'; ?>

如果文件内容是纯 PHP 代码,最好在文件末尾删除 PHP 结束标记。 这可以避免在 PHP 结束标记之后万一意外加入了空格或者换行符,会导致 PHP 开始输出这些空白,但这很可能不是期望的行为。

<?php
echo "Hello world";

// ... more code

echo "Last statement";

// 脚本至此结束,不需要 PHP 结束标记

2.2. 注释

PHP 支持三种形式的注释(两种 C++风格的注释以及 Shell 风格的注释):

<?php
    echo "This is a test"; // This is a one-line c++ style comment
    /* This is a multi line comment
       yet another line of comment */
    echo "This is yet another test";
    echo 'One Final Test'; # This is a one-line shell-style comment
?>

2.3. 变量

PHP 中变量以 $ 符号开头,其后是变量的名称。 变量名是区分大小写的。变量名必须以字母或下划线开头。

<?php
$var = 'Bob';
$Var = 'Joe';     // 变量名称是大小写敏感的,和上面变量不同

echo "$var";      // 输出 "Bob"
echo "$Var";      // 输出 "Joe"
?>

注: $this 是一个特殊的变量,它不能被赋值。

变量默认总是传值赋值。那也就是说,当将一个表达式的值赋予一个变量时,整个原始表达式的值被赋值到目标变量。这意味着,例如,当一个变量的值赋予另外一个变量时,改变其中一个变量的值,将不会影响到另外一个变量。

PHP 也提供了另外一种方式给变量赋值:引用赋值。这意味着新的变量简单的引用(换言之,“成为其别名” 或者 “指向”)了原始变量。改动新的变量将影响到原始变量,反之亦然。 引用赋值的语法是将一个 & 符号加到将要赋值的变量前(源变量)。 如:

<?php
$foo = 'Bob';              // Assign the value 'Bob' to $foo
$bar = &$foo;              // 这是引用赋值
$bar = "My name is $bar";  // 修改 $bar 时,也会修改 $foo

echo $bar;                 // 输出My name is Bob
echo $foo;                 // 也输出My name is Bob
?>

2.3.1. 预定义变量

PHP 提供了大量的预定义变量。由于许多变量依赖于运行的服务器的版本和设置,及其它因素,所以可能并没有详细的说明文档。有关这些变量的详细列表,请参阅 http://php.net/manual/zh/reserved.variables.php

下面是使用预定义变量 $_ENV 的例子:

<?php
echo 'My username is ' .$_ENV["USER"] . '!';
?>

2.3.2. 变量范围

变量的范围即它定义的上下文背景(也就是它的生效范围)。

一般地,PHP 中全局变量在函数中使用时必须声明为 global ,这点和 C 语言是不同的。

<?php
$a = 1; /* global scope */
$b = 2; /* global scope */

function test()
{
    echo $a; // 什么都不会输出,这里 $a 是函数test中没有被赋值的局部变量

    global $b; // 函数内要使用全局变量,需要声明为 global
    echo $b; // 输出 2
}

test();
?>

需要说明的是,那些预定义的超全局变量(Superglobals),可以直接在函数内使用,不需要使用 global 关键字声明,比如 $_ENV, $_GET, $_POST 等这些数组都是超全局变量。

2.4. 常量

PHP 中常量使用 define 函数来定义,不需要前导的 $ 符号,常量名一般约定为大写字母。如:

<?php
define('FOO', 100);
define('BAR', 200);

echo FOO;  // 输出100
echo BAR;  // 输出200
?>

2.4.1. 魔术常量

有九个魔术常量它们的值随着它们在代码中的位置改变而改变。例如 __LINE__ 的值就依赖于它在脚本中所处的行来决定。 这些特殊的常量不区分大小写 ,如表 1 所示。

Table 1: A few "magical" PHP constants
Name Description
__LINE__ The current line number of the file.
__FILE__ The full path and filename of the file with symlinks resolved. If used inside an include, the name of the included file is returned.
__DIR__ The directory of the file. If used inside an include, the directory of the included file is returned. This is equivalent to dirname(__FILE__). This directory name does not have a trailing slash unless it is the root directory.
__FUNCTION__ The function name.
__CLASS__ The class name.
__TRAIT__ The trait name. The trait name includes the namespace it was declared in (e.g. Foo\Bar).
__METHOD__ The class method name.
__NAMESPACE__ The name of the current namespace.
ClassName::class The fully qualified class name.

3. 数据类型

PHP 支持 10 种原始数据类型(Primitive Types),即:

四种标量类型:

  • boolean(布尔型)
  • integer(整型)
  • float(浮点型)
  • string(字符串)

三种复合类型:

  • array(数组)
  • object(对象)
  • callable(可调用)
  • iterable(可遍历)

最后是两种特殊类型:

  • resource(资源)
  • NULL(无类型)

3.1. 布尔类型

这是最简单的类型。要指定一个布尔值,使用常量 TRUEFALSE ,两个都不区分大小写。

要明确地将一个值转换成 boolean,用 (bool) 或者 (boolean) 来强制转换。但是很多情况下不需要用强制转换,因为当运算符,函数或者流程控制结构需要一个 boolean 参数时,该值会被自动转换。

当转换为 boolean 时,以下值被认为是 FALSE:

  • 布尔值 FALSE 本身
  • 整型值 0(零)
  • 浮点型值 0.0(零)
  • 空字符串,以及字符串 "0"
  • 不包括任何元素的数组
  • 特殊类型 NULL(包括尚未赋值的变量)
  • 从空标记生成的 SimpleXML 对象

所有其它值都被认为是 TRUE(包括任何资源 和 NAN)。

下面是一些布尔类型的简单测试:

<?php
var_dump((bool) "");        // bool(false)
var_dump((bool) 1);         // bool(true)
var_dump((bool) -2);        // bool(true)
var_dump((bool) "foo");     // bool(true)
var_dump((bool) 2.3e5);     // bool(true)
var_dump((bool) array(12)); // bool(true)
var_dump((bool) array());   // bool(false)
var_dump((bool) "false");   // bool(true)
?>

3.2. 整型

整型值可以使用十进制,十六进制,八进制或二进制表示,前面可以加上可选的符号( - 或者 + )。

要使用八进制表达,数字前必须加上 0 。要使用十六进制表达,数字前必须加上 0x 。要使用二进制表达,数字前必须加上 0b

<?php
$a = 1234; // 十进制数
$a = -123; // 负数
$a = 0123; // 八进制数 (等于十进制 83)
$a = 0x1A; // 十六进制数 (等于十进制 26)
$a = 0b11111111; // 二进制数字 (等于十进制 255)
?>

注意:如果给定的一个数超出了 integer 的范围,将会被解释为 float。同样如果执行的运算结果超出了 integer 范围,也会返回 float。如:

<?php
$large_number = 9223372036854775807;
var_dump($large_number);                     // int(9223372036854775807)

$large_number = 9223372036854775808;
var_dump($large_number);                     // float(9.2233720368548E+18)

$million = 1000000;
$large_number =  50000000000000 * $million;
var_dump($large_number);                     // float(5.0E+19)
?>

3.3. 浮点型

浮点型(也叫浮点数 float,双精度数 double 或实数 real)可以用以下任一语法定义:

<?php
$a = 1.234;
$b = 1.2e3;
$c = 7E-10;
?>

浮点数的精度有限。尽管取决于系统,PHP 通常使用 IEEE 754 双精度格式。

3.4. 字符串

一个字符串就是由一系列的字符组成。可以用单引号或者双引号包围起来,他们的区别在于单引号不会进行转义,而引号中的变量和特殊字符(如 \n )会进行转义。

除此外,还可以使用类似 Shell 中的 heredoc 句法结构来表示字符串。

使用 . 可以连接两个字符串,使用 .= 可以连接并赋值。如:

<?php
$a = "Hello ";
$b = $a . "World!"; // now $b contains "Hello World!"

$c = "Hello ";
$c .= "World!";     // now $c contains "Hello World!"
?>

3.5. 数组(Ordered Map)

An array in PHP is actually an ordered map.

PHP 中使用 array() 函数(或者 [] )来声明数组,基本语法为:

<?php
$a = array(
           "k1" => "v1",
           "k2" => "v2",
           );

echo $a["k1"]; // 输出 v1

// 从 PHP 5.4 开始,支持 [] 简化数组声明
$b = [
      "k1" => "v1",
      "k2" => "v2",
      ];

echo $b["k1"]; // 输出 v1
?>

直接为数组元素赋值的方式也可以声明数组。如:

<?php
$a["k1"] = "v1";  // 直接为数组元素赋值的方式也可以声明数组
$a["k2"] = "v2";
?>

3.5.1. 省略 key

数组不一定要指定 key,默认 key 是从零开始的整数。如:

<?php
$a = ["foo", "bar", "hello", "world"];  // 没有指定key的数组,默认key依次为整数0, 1, 2, ...
var_dump($a);

// 上面数组 a 相当于:
$b = [
      0 => "foo",
      1 => "bar",
      2 => "hello",
      3 => "world",
      ];

var_dump($b);
?>

还可以只对某些单元指定 key 而对其它单元不指定 key:

<?php
$a = [
      "a",
      "b",
 6 => "c",
      "d",
      ];

var_dump($a);

// 上面数组 a 相当于:
$b = [
      0 => "a",
      1 => "b",
      6 => "c",
      7 => "d",
      ];

var_dump($b);
?>

3.5.2. key 只能是整数或者字符串

PHP 数组中,key 可以是整数或者字符串。而 value 可以是任意类型。

此外 key 会有如下的强制转换:

  • 包含有合法整型值的字符串会被转换为整型。例如键名 "8" 实际会被储存为 8。但是 "08" 则不会强制转换,因为其不是一个合法的十进制数值。
  • 浮点数也会被转换为整型,意味着其小数部分会被舍去。例如键名 8.7 实际会被储存为 8。
  • 布尔值也会被转换成整型。即键名 true 实际会被储存为 1 而键名 false 会被储存为 0。
  • Null 会被转换为空字符串,即键名 null 实际会被储存为 ""。
  • 数组和对象不能被用为键名。坚持这么做会导致警告:Illegal offset type。

如果在数组定义中多个单元都使用了同一个键名,则只使用了最后一个,之前的都被覆盖了。如:

<?php
$a = [
      1    => "a",
      "1"  => "b",
      1.5  => "c",
      true => "d",    // 由key强制转换规则,1, "1", 1.5, true都会转换为1,所以之前的会被覆盖
      "ab" => "bar"
      ];

echo $a[1];    // 输出 d
echo $a["ab"]; // 输出 bar
var_dump($a);

// 上面数组 a 相当于:
$b = [
      1    => "d",
      "ab" => "bar"
      ];

var_dump($b);
?>

3.5.3. 增加元素

当我们在意 key 为什么值时,可以这样增加元素:

<?php
$myArray['key1'] = 'test';   // 如果key1已存在,会修改它;不存在就增加
?>

当我们不在意 key,可以不指定 key,即 $a[] = 'newElement' 的方式来增加元素。 未指定键名时,PHP 将自动使用之前用过的最大整数键名(前面说明键名有两类:整数和字符串)加上 1 作为新的键名。 如:

<?php
$myArray1[] = 'test1';   // 相当于: $myArray1[0] = 'test1'
$myArray1[] = 'test2';   // 相当于: $myArray1[1] = 'test2'

$myArray2[100] = 'ab';
$myArray2["foo"] = 'bar';
$myArray2[] = 'test1';   // 相当于: $myArray1[101] = 'test1'
$myArray2[] = 'test2';   // 相当于: $myArray1[102] = 'test2'

$myArray3["foo"] = 'bar';
$myArray3[] = 'test1';   // 相当于: $myArray3[0] = 'test1'
$myArray3[] = 'test2';   // 相当于: $myArray3[1] = 'test2'
?>

3.5.4. 遍历数组

foreach 语法结构提供了遍历数组的简单方式。foreach 仅能够应用于数组和对象,如果尝试应用于其他数据类型的变量,或者未初始化的变量将发出错误信息。有两种语法:

foreach (array_expression as $value)
    statement
foreach (array_expression as $key => $value)
    statement

下面是 foreach 的例子:

<?php
$colors = array('red', 'blue', 'green', 'yellow');

foreach ($colors as $color) {     // 只关心value
    echo "Do you like $color?\n";
}

$a = array(
    "one" => 1,
    "two" => 2,
    "three" => 3,
    "seventeen" => 17
);

foreach ($a as $k => $v) {      // 即关心key,又关心value
    echo "key = $k, value = $v.\n";
}
?>

3.5.5. 操作数组的一些函数

使用 count 函数可以得到数组元素个数,其它操作数组的一些函数可参考:http://php.net/manual/en/ref.array.php

3.6. NULL

特殊的 NULL 值表示一个变量没有值。NULL 类型唯一可能的值就是不区分大小写的常量 NULL。

在下列情况下一个变量被认为是 NULL:

  • 被赋值为 NULL。
  • 尚未被赋值。
  • 被 unset()。

4. 函数

用户定义的函数声明以关键字 function 开头:

<?php
function foo($arg_1, $arg_2, /* ..., */ $arg_n)
{
    echo "Example function.\n";
    return $retval;
}
?>

函数名对大小写不敏感。如果省略了 return 语句,则返回值为 NULL。

4.1. 参数传递(默认为值传递,可修改为引用传递)

默认情况下,函数参数通过值传递(因而即使在函数内部改变参数的值,它并不会改变函数外部的值)。如果希望允许函数修改它的参数值,必须通过引用传递参数。

如果想要函数的一个参数通过引用传递,可以在函数定义中该参数的前面加上符号 & ,如:

<?php
function add_some_extra(&$string) // 参数前加了 & ,就是“引用”方式传递参数
{
    $string .= 'and something extra.';
}

$str = 'This is a string, ';

add_some_extra($str); // 调用函数add_some_extra会修改它的参数

echo $str;    // 输出 'This is a string, and something extra.'
?>

4.2. 默认参数

PHP 函数支持默认参数,其使用实例如下:

<?php
function makecoffee($type = "cappuccino")  // 为参数 $type 指定了默认参数
{
    return "Making a cup of $type.\n";
}
echo makecoffee();            // Making a cup of cappuccino.
echo makecoffee(null);        // Making a cup of .
echo makecoffee("espresso");  // Making a cup of espresso.
?>

默认值必须是常量表达式,不能是诸如变量,类成员,或者函数调用等。

4.3. 可变数量的参数列表

PHP 在用户自定义函数中支持可变数量的参数列表。在 PHP 5.6 及以上的版本中,由 ... 语法实现,如:

<?php
function sum(...$numbers) {  // 这是可变数量的参数
    $acc = 0;
    foreach ($numbers as $n) {
        $acc += $n;
    }
    return $acc;
}

echo sum(1, 2, 3, 4);   // 输出 10
?>

4.4. 匿名函数

匿名函数(Anonymous functions),允许临时创建一个没有指定名称的函数。最经常用作回调函数(callback)参数的值。如下面例子中内置函数 preg_replace_callback 的第 2 个参数是匿名函数:

<?php
echo preg_replace_callback('~-([a-z])~', function ($match) {
    return strtoupper($match[1]);
}, 'hello-world');
// 输出 helloWorld
?>

匿名函数也可以作为变量的值来使用,如:

<?php
$greet = function($name)
{
    printf("Hello %s\n", $name);
};

$greet('World'); // 输出 Hello World
$greet('PHP');   // 输出 Hello PHP
?>

4.5. 参数和返回值的类型声明

在 PHP7 中,可以为函数的参数和返回值声明类型,如:

<?php
function add2ints(int $a, int $b): int {
//                 ^       ^        ^
//            类型声明  类型声明  类型声明
    return $a + $b;
}

echo add2ints(1, 2);
?>

不过,声明类型时不能使用类型别名,如 boolean 是 bool 的别名,声明布尔类型时必须写为 bool,不能写为 boolean:

<?php
function test(boolean $param) {} // 错误的类型声明

test(true);    // 会报错。把函数test的参数类型声明从boolean修改为bool后变正常
?>

默认,PHP 会把错误的类型转换为所声明的类型,如果 PHP 文件中指定了 declare(strict_types=1); ,则不会进行转换,当类型不匹配时直接抛出 TypeError。 如:

<?php
declare(strict_types=1);

function add2ints(int $a, int $b): int {
    return $a + $b;
}

echo add2ints(1, 2);
echo add2ints(1.1, 2);  // 这一行仅当文件中指定了 declare(strict_types=1); 后才会抛出TypeError
?>

5. 类和对象

自 PHP 5 起完全重写了对象模型以得到更佳性能和更多特性。这是自 PHP 4 以来的最大变化。PHP 5 具有完整的对象模型。

下面是类的定义及基本使用:

<?php
class SimpleClass
{
    // 声明属性
    public $var1 = "a default value\n";

    // 声明方法
    public function displayVar() {
        echo $this->var1;
    }
}

$instance = new SimpleClass();  // 创建对象

$instance->displayVar();  // 调用对象方法
echo $instance->var1;      // 使用对象属性
?>

6. 参考

Author: cig01

Created: <2018-09-10 Mon>

Last updated: <2019-03-11 Mon>

Creator: Emacs 27.1 (Org mode 9.4)