PHP简单入门

1.PHP内核Zend

PHP由内核Zend引擎和扩展层组成,PHP内核负责处理请求、完成文件流错误处理等操作,Zend引擎可以将PHP程序文件转换成可在虚拟机上运行的机器语言,扩展层提供一些应用层操作需要的函数类库等,比如数组和MySQL数据库的操作等。

Zend引擎是用C语言实现的,将PHP代码通过词法语法解析成可执行的opcode并实现相应的处理方法、基本的数据结构内存分配和管理等,对外提供相应的可供调用的API方法。Zend引擎是PHP的核心,所有的外围功能都是围绕它实现的。扩展层通过组件的方式提供各种基础服务、内置函数,标准库都是通过它实现的。用户也可以编写自己的扩展来实现特定的需求。服务端应用编程接口(Server Application Programming Interface, SAPI),通过一系列钩子函数使得PHP可以和外围交互数据。我们平时编写的PHP程序就是通过不同的SAPI方式得到不同的应用模式,如通过WebServer实现的Web应用和在命令行下运行的脚本等。一段PHP程序被执行的时候会先被解析成opcode指令,然后在虚拟机中按顺序执行,由于PHP本身是用C语言开发的,所以其在执行的时候调用的都是C的函数。opcode是PHP程序执行的最基本单位。

HashTable是Zend的核心数据结构,实现了PHP里几乎所有的功能,支持key->value查询,添加删除的复杂度是O(1),支持线性遍历和混合类型。在HashTable中既有key->value形式的散列结构,也有双向链表模式,使得它能够非常方便地支持快速查找和线性遍历。Zend的散列结构是典型的hash表模型,通过链表的方式来解决冲突。Zend的HashTable是一个自增长的数据结构,当hash表数目满了之后,其本身会动态地以2倍的方式扩容并重新布置元素位置,初始大小均为8。另外,在进行key->value快速查找的时候,Zend本身还做了一些优化,通过空间换时间的方式加快速度。比如在每个元素中都会用一个变量nKeyLength标识key的长度以做快速判定。Zend HashTable通过一个链表结构实现了元素的线性遍历。理论上,做遍历使用单向链表就够了,使用双向链表的主要目的是为了快速删除链表元素,避免遍历。PHP是一门弱类型语言,本身不严格区分变量的类型。PHP在声明变量的时候不需要指定类型。PHP在程序运行期间可能进行变量类型的隐式转换。和其他强类型语言一样,程序中也可以进行显式的类型转换。Zval是Zend中另一个非常重要的数据结构,用来标识并实现PHP变量。

2.php核心数据结构

Zval主要由以下3部分组成。

  • Type指定了变量所述的类型(整数、字符串、数组等)。
  • refcount&is_ref用来实现引用计数。
  • value是核心部分,存储了变量的实际数据。

Zval用来保存一个变量的实际数据。因为要存储多种类型,所以zval是一个union,也由此实现了弱类型。引用计数在内存回收、字符串操作等地方使用得非常广泛。PHP中的变量就是引用计数的典型应用。Zval的引用计数通过成员变量is_ref和ref_count实现。通过引用计数,多个变量可以共享同一份数据,避免频繁复制带来的大量消耗。

在进行赋值操作时,Zend将变量指向相同的Zval,同时ref_count++,在unset操作时,对应的ref_count-1。只有ref_count为0时才会真正执行销毁操作。如果是引用赋值,Zend就会修改is_ref为1。PHP变量通过引用计数实现变量共享数据,当试图写入一个变量时,Zend若发现该变量指向的Zval被多个变量共享,则为其复制一份ref_count为1的Zval,并递减原Zval的refcount,这个过程称为“Zval分离”。可见,只有在有写操作发生时,Zend才进行复制操作,因此也叫copy-on-write(写时复制)。对于引用型变量,其要求和非引用型相反,引用赋值的变量间必须是捆绑的,修改一个变量就修改了所有捆绑变量。

3.php7的新特性

相较于以前的版本,PHP 7在语言语法层面和底层架构层面都有一些改进。在语法层面的改进主要是增加了一些新特性、移除了一些扩展、改变了错误异常处理等。在底层结构方面,改变了存储各种变量的Zval和Zend_String结构体、优化了Zend Array的HashTable、改进了函数的调用机制等。这些底层结构的改进大幅提升了PHP的执行效率,使得其执行速度比PHP 5高出一倍左右。PHP是一个弱类型的语言,不过在PHP 7中支持变量类型的定义,引入了一个开关指令declare(strict_type=1);。这个指令一旦开启,就会强制当前文件下的程序遵循严格的函数传参类型和返回类型。不开启strict_type, PHP将会尝试转换成要求的类型;开启之后,PHP不再做类型转换,类型不匹配就会抛出错误。要使用严格模式,一个declare声明指令必须放在文件的顶部。这意味着严格声明标量是基于文件可配的。这个指令不仅影响参数的类型声明,还影响函数的返回值声明。

PHP 7中的新特性主要有以下几点:

  • (1)标量类型声明。
  • (2)函数返回值类型声明。
  • (3)新增null合并运算符。
  • (4)新增组合比较符。
  • (5)支持通过define()定义常量数组。
  • (6)新增支持匿名类。
  • (7)支持Unicode codepoint转译语法。
  • (8)更好的闭包支持。
  • (9)为unserialize()提供过滤。
  • (10)新增加IntlChar类。
  • (11)支持use语句从同一namespace导入类、函数和常量。
  • (12)新增整除函数intdiv()。
  • (13)session_start()支持接收数组参数。

4.php数据类型

数据类型是指对数据的抽象描述,比如“整型数据”就是对所有整数数字的抽象。PHP的数据类型包括String(字符串)、Integer(整型)、Float(浮点型)、Boolean(布尔型)、Array(数组)、Object(对象)、NULL(空值)7种,本节介绍这些数据类型的定义和使用。

  • 字符串
$str  = "hello  world";
eche $str;
  • 整型
$num = 10;
  • 浮点型
$price = 1.0
  • Boolean
$isFlag = true;
  • array
$arr = array("hello","world"=>array("php","is","the","best"))
  • object
class Hello {
  var $str;
  
  function get_str() {
    return $this->str;
  }

  function set_str($str = "hello world") {
    $this->str = str;
  }
}
  • 常量
    可以用define定义,也可以用const定义(php7)
    可以是标量和资源。
define ("Foo", "bar");
const Version = "1.0.0";

自定义常量尽量不要用下划线__Name__,一般留给内置的预定义常量

  • 预定义常量
__LINE__ 行号
__FILE__ 文件路径和文件名
__DIR__ 文件所在的目录
__FUNCTION__ 函数名
__CLASS__ 类名
__TRAIT__ trait的名字
__METHOD__类的方法名
__NAMESPACE__ 命名空间名

4.php流程控制

  • if else
if ($a < $b) {
  return $a;
} else if ($a == $b) {
  return $b;
} else {
  return $b;
}
  • switch
switch  ($num1) {
  case $num1 == "hello":
    echo $num1;
    break;
  case $num1  ==  "world":
    echo $num1;
    break;
  default:
    echo  "hello world";
    break;
}
  • while
while ($num < 10)  {
  echo $num;
  -$num;
}
  • do while
do {
  echo $num;
}  while  ($num <  10);
  • for
for  ($num = 0; $num < 100;  $num++)  {
  echo $num;
}
  • foreach
foreach ($num_array as $num) {
  echo $num;
}

foreach($num_array as $key =>  $value)  {
  echo $key;
  echo $value;
}

在PHP 5版本中,当foreach开始循环执行时,每次数组内部指针都会自动向后移动一个单元,但是在PHP 7中却不是这样

在PHP 7中,按照值进行循环时,foreach是对数组的复制操作,在循环过程中对数组的修改不会影响循环行为,但在PHP 5中却会有影响。

在PHP 7中按照引用循环的时候对数组的修改会影响循环,在PHP 5中则不会改变。

  • goto
    goto语句可以用来跳转到程序中的另一个位置。该目标位置可以用目标名称加上冒号来标记,而跳转指令是goto之后接上目标位置的标记。PHP中对goto语句有一定限制,即目标位置只能位于同一个文件和作用域,也就是说无法跳出一个函数或类方法,也无法跳入另一个函数、其他循环或者switch结构中。可以跳出循环或者switch,goto语句常用来代替多层的break语句。
goto  a;
echo "hello";
a:
echo  "world";

主要用来跳出复杂循环

for ($num =  0;  $num < 100;  ++$num)  {
  if ($num  === 3)   {
    echo "is  3";
    goto a;  
}
  echo  $num;
}
a:
ehco  "end  loop";
  • 包含语句用于在PHP文件中引入另一个文件,这样有利于代码重用。PHP中共有4个包含外部文件的方法,分别是include、include_once、require、require_once。
  • include
    include语句包含并运行指定文件。被包含文件先按参数给出的路径寻找,如果没有给出目录(只有文件名),就按照include_path(在配置文件中可查看include_path)指定的目录寻找。如果在include_path下没找到该文件,那么include最后会在调用脚本文件所在的目录和当前工作目录下寻找。如果最后仍未找到文件,include结构就会发出一条警告,例如:

当一个文件被包含时,其中所包含的代码继承了include所在行的变量范围。从该处开始,调用文件在该行处可用的任何变量在被调用的文件中也都可用。不过所有在包含文件中定义的函数和类都具有全局作用域。如果include出现于调用文件中的一个函数里,那么被调用的文件中所包含的所有代码将表现得如同它们是在该函数内部定义的一样。所以它将遵循该函数的变量范围。此规则的一个例外是魔术常量,它们是在发生包含之前就已被解析器处理的.

  • include_once
    include_once和includ效果类似,唯一的区别是如果文件已经被包含,就不会再被包含。
    用于在脚本执行期间同一个文件只会执行一次的情况确保它只被执行一次,以避免重复定义,变量重新赋值的问题。

  • require
    require和include几乎一模一样,不同的是当包含不存在的文件时,require会爆出一个Fatal Error错误并且终止执行,include则会发出一个warning但继续执行代码。

  • require_once
    require_once功能和include_once效果基本上相同,唯一的区别是php会检查文件是否存在。

5.函数

将一段代码封装成一段函数,在调用的时候只需要这个函数名即可。

function foo($argc_1,  $argc_2) {
  state;
}

其中foo是函数名,argc_1和argc_2是函数的参数。函数的参数可以是零个或者任意个。任何有效的php代码都可以写在函数体内。php的函数作用域是全局的,任何一个文件内的函数定义后可以在该文件的任何地方调用。

function add_sum($num1, $num2)  {
  return $num1 + $num2;
}

6.函数的参数

PHP支持按值传递参数(默认),通过引用传递参数及默认参数,也支持可变长度参数列表。PHP支持函数参数类型声明。

-按照值传递

function  add($num1, $num2) {
   $num1 += $num2;
}

echo $num1; // won't  change
  • 按照参数传递
function add(&$num1, $num2) {
  $num1 += $num2;
}
echo $num1;//change
  • 默认参数
function  add($arr =  array("hello","world"), $num1  = 100) {
}
  • 参数的类型声明
    php5已经引入参数类型声明,如果给定的值不是合法类型,php5会返回一个Fatal Error,php7则会返回一个 TypeError Exception
class/interface       php5.0
Array                 php5.1
Callable              php5.4//有效的回调用
Bool                   php7
Float                  php7
Int                    php7
String                 php7
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 156,757评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,478评论 1 289
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,540评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,593评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,903评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,329评论 1 210
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,659评论 2 309
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,383评论 0 195
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,055评论 1 238
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,337评论 2 241
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,864评论 1 256
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,227评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,820评论 3 231
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,999评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,750评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,365评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,260评论 2 258