1、php if...else 在html中的替代语法
<?php $name = 'ok' ?> <?php if ($name == '1ok') : ?> <div>this is first</div> <?php else: ?> <div>this is second</div> <?php endif ?>
2、php for在html中的替代语法
<?php for ($i = 0; $i < 10; $i++): ?> <div>are you ok???</div> <?php endfor ?>
3、php switch在html中的替代语法
<?php $a = 6 ?> <?php switch (true): ?> <?php case $a == 3: ?> <div>this is first</div> <?php break; ?> <?php case $a == 4: ?> <div>this is second</div> <?php break; ?> <?php case $a == 5: ?> <div>this is third</div> <?php break; ?> <?php default: ?> <div>没有可匹配的了</div> <?php endswitch ?>
4、require,require_once,include,include_once的区别
require与include的用法一样,通常为引用一个文件,但是require的错误级别高,一旦遇到错误那么主停止运行,include的错误级别低,遇到一般性的错误还是会往下执行语句
如:
<?php ini_set('display_errors', true); require './index1.php'; //include './index1.php'; echo 'are you ok???' ?>
引入一个不存在的文件,require会报Fatal error,并且不会往下执行语句,但是include会输出are you ok???这个语句
require_once 同include_once除了以上的区别外其他的作用一样,在一个文件引入多次的情况下,只执行一次,以防重复引用
5、常用超全局作用域
可以接收表单或者超链接发送过来的数据
$_GET['参数名称‘] 可以通过表单发送过来的数据进行接收数据,也可以通过超链接的形式接收数据如下
<a href='./index.php?name=username&psd='aaa'>跳转</a>
那么在Php端的数据接收方式如下代码
<?php header('content_type:text/html,charset=utf8'); ini_set('display_errors',true); $name=$_GET['username']; $pwd=$_GET['psd']; echo '用户名'.$name,'密码'.$pwd; ?>
$_POST['参数名称']接收通过Post方式传输过来的数据,用法同get,但是不支持超链接传输
$_SERVER 返回的是服务器以及客户端的信息,如host信息,HTTP_USER_AGENT信息等
$_REQUEST 可以接收get请求,post请求,cookie等
$_FILES接收的是上传的文件的信息(注意上传文件在表单里面采用的是Post方式,同时设置enctype="multipart/form-data")
<?php var_dump($_FILES); ?> <!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>test</title> </head> <body> <form action="./test.php" method="post" enctype="multipart/form-data"> <input type="file" name="file"> <input type="submit" value="提交"> </form> </body> </html>
输出的结果如下
array(1) { ["file"]=> array(5) { ["name"]=> string(22) "method API整理.docx" //表示文件名称 ["type"]=> string(71) "application/vnd.openxmlformats-officedocument.wordprocessingml.document" //表示文件类型 ["tmp_name"]=> string(44) "C:\Users\yufen\AppData\Local\Temp\php465.tmp" //上传文件的临时存放的地址 ["error"]=> int(0) //错误 ["size"]=> int(15805) //文件大小 } }
那么接收改变文件的名字可以用move_upload_file函数进行处理
6、变量的引用传值
变量的引用传值是用&来表示的,当采用引用传值后,一方的改变会影响的另一方的值,但是一方的删除则不会影响另一方的值
<?php header('content-type:text/html;charset=urf8'); $first = 'are you ok???'; $second =& $first; $second = 'good bye'; echo $first; //输出 good bye unset($first); echo '<br>'; echo $second; //输出 good bye $first的删除不会影响到$second的值 ?>
在php中默认的引用传值方式有
在对象中的默认的引用传值(注意区别与js,在数组中,js存在引用传值 ,而在php中数组不存在引用传值)
<?php header('content-type:text/html;charset=utf8'); ini_set('display_errors', true); $arr = [ 'first' => 'are you ok???', 'second' => 'today is good day' ]; $arr1 = $arr; $arr1['first'] = 'haha'; var_dump($arr); var_dump($arr1); //输出 //array(2) { // ["first"]=> // string(13) "are you ok???" // ["second"]=> // string(17) "today is good day" //} //array(2) { // ["first"]=> // string(4) "haha" // ["second"]=> // string(17) "today is good day" //} ?>
在类中存在引用传值
<?php header('content-type:text/html;charset=utf8'); ini_set('display_errors', true); class Person { public $name; } $p1 = new Person(); $p1->name = 'Leo'; $p2 = $p1; $p2->name = 'Jim'; echo $p1->name; //输出 Jim; echo $p1->name; //输出 Jim; ?>
7、函数里的静态变量static
在php中如果一个函数运行完,那么里面的变量会被销毁,不会被保存,如果有需求要里面的变量继续存在,那么可以定义一个静态的变量(static修饰),静态变量在函数中的作用是保存已定义好的变量,不再重新定义,但是在全局变量里面静态变量就没有意义了
<?php ini_set('display_errors', true); function addNum() { $num = 0; $num++; echo $num; } addNum(); addNum(); addNum(); //输出 111; function addStaticNum() { static $num = 0; $num++; echo $num; } echo '<br>'; addStaticNum(); addStaticNum(); addStaticNum() //输出 123 ?>
8、局部变量与全局变量的互相转换
局部变量与全局变理的互相转换是通过$GLOBALS与global来声明互相转换的,但是前者是以数组形式进行的,后者是以变量形式进行的,祥见例子
<?php ini_set('display_errors', true); $name = 'Leo'; $age = 30; function getName() { //对全局变量进行声明 global $name, $age; echo $name, $age; //输出 Leo30 //对全局变量进行更改 $name = 'are you ok???'; echo $GLOBALS['name'], $GLOBALS['age']; //(注意以上的写法,里面是字符串)输出 are you ok???30 global $say; $say = 'today is good day'; //对全局变量进行声明,不建议在函数内部进行全局变量的声明 } getName(); echo $say; //输出 today is good day ?>
$GLOBALS可以访问到全部的全局变量可以用var_dump($GLOBALS)来查看
9、变量中常用的三个函数 isset unset empty
isset(mixed $val,...)检测变量是否已经定义
unset(mixed $val,...)销毁指定的变量
empty(mixed $val)判断指定的变量是否是空 如'',0,0.00,false,[],null等
<?php header('content-type:text/html;charset=utf8'); ini_set('display_errors', true); $name = '123'; var_dump(isset($name));//输出true var_dump(empty($name));//输出false unset($name); var_dump(isset($name));//输出false ?>
10、常量
常量一经定义是不能修改和删除的,只能等程序自动释放内存
<?php header('content-type:text/html;charset=utf8'); ini_set('display_errors', true); //方式一,通过define来定义,但是大写的词必需添加引号 define('NAME', 'leo'); define('AGE', 20); echo NAME, AGE; define('ARR', [1, 23, 4, 5, 6]); var_dump(ARR); echo '<hr/>'; //方式二 const TOKEN = 'are you ok???'; echo TOKEN; const WEAPON = [ 'ARROW' => 1, 'GUN' => 2, 'AXE' => 3 ]; const CNAME = [ WEAPON['ARROW'] => '箭', WEAPON['GUN'] => '枪', WEAPON['AXE'] => '斧' ]; var_dump(WEAPON); var_dump(CNAME); ?>
11、魔术常量
__LINE__ 返回当前代码的行号
__DIR__返回当前的目录
__FUNCITON__返回当前函数的名称
__CLASS__返回类的名称
<?php header('content-type:text/html;charset=utf8'); ini_set('display_errors', true); echo(__LINE__); //输出 4 echo(__DIR__); //输出 C:\wnmp\nginx\www function test() { echo __FUNCTION__; } test(); //输出 test echo '<hr>'; Class Check { public function __construct() { echo __CLASS__; } public function init() { echo __CLASS__; } } $tc = new Check(); $tc->init(); //输出 Check Check; ?>
12、heredoc与nowdoc
<?php header('content-type:text/html;charset=utf8'); ini_set('display_errors', true); $name = 'leo'; //可以解析变量 $heredoc = <<<AAA <div>my name is {$name}</div> AAA; echo $heredoc; //不能解析变量 $nowdoc = <<<'AAA' <div>my name is {$name}</div> AAA; echo '<br>'; echo $nowdoc; ?>
13、php的最大值可以用 PHP_INT_MAX来查看,最大的位数PHP_INT_SIZE;php的错误控制符@
<?php header('content-type:text/html;charset=UTF8'); ini_set('display_errors', true); echo @$a; ?>
14、数组的运算
两个数组相加,相当于合并,如果有相同项前者会覆盖后者
<?php header('content-type:text/html;charset=UTF8'); ini_set('display_errors', true); $a1 = ['name' => 'leo', 'age' => 30]; $a2 = ['age' => 20, 'hobby' => 'sport']; var_dump($a1 + $a2); //输出 array(3) { ["name"]=> string(3) "leo" ["age"]=> int(30) ["hobby"]=> string(5) "sport" } $arr = [ 'name' => 'aaa', 'age' => 20, 'sex' => 'man', 'hobby' => 'sport' ]; $arr1 = [ 'name' => 'aaa', 'age' => 20, 'sex' => 'man', 'hobby' => 'sport' ]; var_dump($arr == $arr1); //输出true var_dump($arr === $arr1) //输出true ?>
15、goto语句(该方法尽量少用)
<?php header('content-type:text/html;charset=UTF8'); ini_set('display_errors', true); goto a; echo 'are you ok????'; a: echo 'today is good day!!!'; //输出 today is good day!!! ?>
16、return的使用,不仅在函数中可以进行返回操作,同时也可以在页面进行return 进行停止页面,也可以在Php文件中return通常用作配置文件中
<?php header('content_type:text/html,charset=utf8'); //输出页面 return array( 'name' => 'leo', 'age' => 20, 'sex' => 'man' ); ?> <?php //在接收页面 header('content-type:text/html;charset=UTF8'); ini_set('display_errors', true); $arr = include('./index.php'); var_dump($arr); ?>
17、可变函数
当变量名加上括号,那么Php系统会尝试着解析成函数如下
<?php header('content-type:text/html;charset=UTF8'); ini_set('display_errors', true); $a = 'sum'; function sum($a, $b, $c) { return $a + $b + $c; } echo $a; //输出 sum; echo $a(1, 2, 3); //输出 6 ?>
18、回调函数
回调函数的调用可以分成两种方式,如下例子
<?php header('content-type:text/html;charset=UTF8'); ini_set('display_errors', true); function sum($a, $b) { return $a + $b; } function getSum($a, $b) { return sum($a, $b); } function getSum1($a, $b, $c) { return $c($a, $b); } echo getSum(1, 3); //输出4; echo getSum1(2, 4, 'sum'); //输出6 ?>
19、匿名函数
注意use在函数中的使用
<?php header('content-type:text/html;charset=UTF8'); ini_set('display_errors', true); $test = (function () { $sum = function ($a, $b) { return $a + $b; }; $say = function () { echo 'are you ok???'; }; return function ($a, $b) use ($sum, $say) { $say(); return $sum($a, $b); }; })(); echo($test(1, 3)); //输出 are you ok???4
20、递归调用
一个函数内部再次调用自己,并且有条件的退出调用,这种调用方法称作递归调用
<?php header('content-type:text/html;charset=UTF8'); ini_set('display_errors', true); //求斐波那契数列,每个数字都是由第面两个数的和,第一个数和第二数除外 //1,1,2,3,5,8,13,21,34... //作用递归函数求 function getValue($num) { if ($num == 1 || $num == 2) { return $num; } return getValue($num - 1) + getValue($num - 2); } echo getValue(7); ?>
21、面向对象的构造函数
a、构造函数有三个修饰 public ,protected,private ,默认是Public
b、构造函数没有返回值,不能return,写法是固定的,不能修改
c、__construct是系统自调用,不能人为调用
d、如果在一个类中没有定义构造函数,那么就会默认一个构造函数
注意:在老的php版本里面,会把类名定义成里面的一个内置方法,那么相当于__construct的作用
<?php header('content-type:text/html;charset=utf8'); ini_set('display_errors', true); class Person { public $name; public $age; public $food; public function __construct($name, $age, $food) { $this->name = $name; $this->age = $age; $this->food = $food; echo $this->name, $this->age, $this->food; } } $p = new Person('aaa', 20, 'cake'); //输出 aaa20cake ?>
22、析构函数
析构函数__destruct方法
a、在页面运行完后,系统自动释放缓存的时候被马上就会调用(在删除的时候,是按照后进先出的原则,即后声明的先执行析构函数)
b、在所有指向这个函数的方法都销毁后被调用
c、给程序员一个机会去及时的回收创建的资源(如关闭数据库)
<?php header('content-type:text/html;charset=utf8'); ini_set('display_errors', true); class Person { public $name; public $age; public $food; public function __construct($name, $age, $food) { $this->name = $name; $this->age = $age; $this->food = $food; echo $this->name, $this->age, $this->food; } public function __destruct() { echo __CLASS__ . '这个对象已经被销毁了'; } } $p = new Person('aaa', 20, 'cake'); $p = null; echo 'today is good day'; //输出 aaa20cake Person这个对象已经被销毁了 today is good day ?>
23、魔术方法
a、魔术方法都是系统提供的,程序员使用即可
b、所有的魔术方法都是以__开头的,所以在写自定义函数的时候不要以__开头
c、魔术方法是在满足某个条件的时候,有系统自动调用
A、魔术方法之__get 和__set的使用,当访问和设置类里不公开的属性的情况下,可以自动触发类里面的__get和__set方法
<?php header('content-type:text/html;charset=utf8'); ini_set('display_errors', true); class Person { public $name; protected $age; private $sex; public function __construct($name, $age, $sex) { $this->name = $name; $this->age = $age; $this->sex = $sex; } /**魔术方法,获取内部不能访问的方法 * @param $pro_name指定的变量名 * @return string */ public function __get($pro_name) { //property_exists是判断某个类里面是否含有指定的方法如下 if (property_exists($this, $pro_name)) { return $this->$pro_name; } else { return '没有这个属性'; } } /**设置内部的变量 * @param $pro_name变量名 * @param $pro_val变量值 */ public function __set($pro_name, $pro_val) { if (property_exists($this, $pro_name)) { $this->$pro_name = $pro_val; } } } $p1 = new Person('aaa', 30, 'man'); var_dump($p1->name); //输出 aaa echo '<br>'; var_dump($p1->age); //输出 30 $p1->sex = 'woman'; echo '<br>'; var_dump($p1->sex); //输出 woman ?>
通过魔术方法__get来调用方法(常用)
<?php header('content-type:text/html;charset=utf8'); ini_set('display_errors', true); class Person { public $name; public $age; public function __construct($name, $age) { $this->name = $name; $this->age = $age; } public function getName() { return $this->name; } public function __get($pro_name) { if (property_exists($this, $pro_name)) { return $this->$pro_name; } else if (method_exists($this, $pro_name)) { return $this->$pro_name(); } return '没有这个方法或者属性'; } } $p = new Person('leo', 30); var_dump($p->getName); ?>
注意:如果对一个不存在的变量进行赋值,那么会动态的在类里添加一个Public的属性,这个可以使用__set来阻止
注意,property_exists(class,per)在判断是否存在某个属性的时候,先判断是否存在,然后再去判断类里面是否设置过指定的属性,原理同isset判断类里的属性是否存在一样(这个主要是判断变量是否存在的,如果是判断方法是否存在的,那么要使用method_exists(class,per))来判断
B、__isset和__unset魔术方法
当调用isset和empty两个方法来判断类里的属性时,那么会自动触发类里的__isset的魔术方法
当调用unset这个方法来删除类里的属性时,那么会自动触发类里的__unset的魔术方法
以上两个方法接收一个参数,是属性的名字
<?php header('content-type:text/html;charset=utf8'); ini_set('display_errors', true); class Person { public $name; private $age; private $sex; private $salary; public function __construct($name, $age, $sex, $salary) { $this->name = $name; $this->age = $age; $this->sex = $sex; $this->salary = $salary; } public function __isset($pro_name) { return property_exists($this, $pro_name); } public function __unset($pro_name) { if (property_exists($this, $pro_name)) { unset($this->$pro_name); } } public function __get($pro_name) { if (property_exists($this, $pro_name)) { return $this->$pro_name; } return '该属性不存在'; } } $p = new Person('leo', 20, 'man', 10000); var_dump(isset($p->sex)); //输出 true; unset($p->salary); var_dump($p->salary); //会报错 并且返回Null ?>
C、__toString魔术方法
当打印实例化的类的时候,会触发__toString的方法,打印出指定的东西,这个是为了充当debug来使用,没有参数,但是返回的是一个字符串
<?php header('content-type:text/html;charset=utf8'); ini_set('display_errors', true); class Person { public $name; private $age; private $sex; public function __construct($name, $age, $sex) { $this->name = $name; $this->age = $age; $this->sex = $sex; } public function __toString() { return "name:{$this->name},age:{$this->age},sex:{$this->sex}"; } } $p = new Person('aaa', 20, 'man'); echo $p; //输出 name:aaa,age:20,sex:man ?>
D、魔术方法__clone
当调用clone方法的时候就会触发类里面的__clone方法,如果不改变其他值时,两个对象的属性和值是相同的,但是拥有独立的内存空间,如果想阻止克隆,那么把魔术变量设置为private便可
<?php header('content-type:text/html;charset=utf8'); ini_set('display_errors', true); class Person { public $name; public $age; public $sex; public function __construct($name, $age, $sex) { $this->name = $name; $this->age = $age; $this->sex = $sex; } public function __clone() { // $this->name = 'are you ok???'; //可以改变克隆时的值 } // 这个方法可以阻止克隆 // private function __clone(){ // // } } $p1 = new Person('aaa', 20, 'man'); $p2 = clone $p1; var_dump($p1 == $p2); //返回true 对象里面的值和属性一样,那么相对比较是相等的 var_dump($p1 === $p2); //返回false 对象里的内存空间指向不一样,那么绝对比较是不相等的 //如果想阻止克隆,那么只要把__clone设置为Private便可 ?>
E、魔术方法__call
当需要调用类里面不能调用的方法(注意是方法,区别__get这个魔术方法)private或者是protected时候会自动触发__call这个魔术方法,执行的顺序是,先去调用是否有公开的API,如果没有才会去调用__call的方法
<?php header('content-type:text/html;charset=utf8'); ini_set('display_errors', true); class Person { public $name; protected $hobby; public function __construct($name, $hobby) { $this->name = $name; $this->hobby = $hobby; } //公共的方法 public function showHobby() { if (!empty($this->hobby)) { foreach ($this->hobby as $key) { echo $key; } } } //私有的方法 private function getSum() { $arr = func_get_args(); if (!empty($arr)) { return array_sum($arr); } return 0; } /**调用私有方法的魔术变量 * @param $func_name * @param $params * @return mixed|string */ public function __call($func_name, $params) { var_dump(method_exists($this, $func_name)); if (method_exists($this, $func_name)) { return call_user_func_array([$this, $func_name], $params); } else { return '没有你要调用的方法,请检查'; } } } $p = new Person('aaa', [ 'a' => 'reading', 'b' => 'writing' ]); $p->showHobby(); //输出 reading writing echo '<hr/>'; var_dump($p->getSum(1, 2, 3, 4, 5, 6, 7)); //输出 28 ?>
利用__call魔术方法来实现方法的重载
<?php header('content-type:text/html;charset=utf8'); ini_set('display_errors', true); class Person { public $name; public function __construct($name) { $this->name = $name; } public function getSum($val1, $val2) { return $val1 + $val2; } public function getMax($val1, $val2, $val3) { return max($val1, $val2, $val3); } public function __call($method_name, $params) { if ($method_name == 'deal' && count($params) == 2) { return call_user_func_array([$this, 'getSum'], $params); } else if ($method_name == 'deal' && count($params) == 3) { return call_user_func_array([$this, 'getMax'], $params); } return 'are you ok???'; } } $p = new Person('leo'); echo $p->deal(1, 2) . '<br>'; //输出 3 echo $p->deal(4, 5, 6); //输出 6 ?>
利用__callStatic来实现静态方法的重载
<?php header('content-type:text/html;charset=utf8'); ini_set('display_errors', true); class Person { public $name; public static $getSum; public static $getMax; public function __construct($name) { $this->name = $name; } private static function countSum($val1, $val2) { return $val1 + $val2; } private static function countMax($val1, $val2, $val3) { return max($val1, $val2, $val3); } public static function __callStatic($method_name, $params) { if ($method_name = 'sCount' && count($params) == 2) { return call_user_func_array(['self', 'countSum'], $params); } else if ($method_name = 'sCount' && count($params) == 3) { return call_user_func_array(['self', 'countMax'], $params); } return '对不起,没有这个静态方法'; } } var_dump(Person::sCount(1, 6)); var_dump(Person::sCount(1, 6, 9)); //输出 int(7) int(9) ?>
F、类的自动加载,使用__autoLoad方法
__autoLoad是系统方法,有点像魔术方法,但是不是魔术方法
这个方法主要功能是完成类的自动加载,当程序员使用到一个未定义的类的时候,就会自动触发__autoLoad这个函数
//Index.php里的文件 <?php header('content-type:text/html;charset=utf8'); ini_set('display_errors', true); class Index { public $name; public $age; private $salary; public function __construct($name, $age, $salary) { $this->name = $name; $this->age = $age; $this->salary = $salary; } public function __get($pro_name) { if (property_exists($this, $pro_name)) { return $this->$pro_name; } else { return '这个类里面是没有这个名字的'; } } } ?>
//test.php里的文件 <?php header('content-type:text/html;charset=utf8'); ini_set('display_errors', true); /**当方法在使用到这个类的时候,没有发现这个类,那么就会调用__autoLoad这个方法去加载类 * 接收一个参数,即所调用的类的类名 * @param $class_name */ function __autoload($class_name) { require "./{$class_name}.php"; } $I = new Index('aaa', 30, 10000); echo $I->salary; //输出 10000 ?>
如果遇到多个引入文件的情况下,可以用一个数组进行封装, 这样比较方便操作
<?php header('content-type:text/html;charset=utf8'); ini_set('display_errors', true); $class_name_arr = [ 'Index' => './Index.php' ]; function __autoload($class_name) { global $class_name_arr; require_once $class_name_arr[$class_name]; } //错误写法 //function test()use ($class_name_arr) { // var_dump($class_name_arr); //}; //正确写法 //闭包的语法很简单,需要注意的关键字就只有use,use意思是连接闭包和外界变量。 $test = function () use ($class_name_arr) { var_dump($class_name_arr); }; $I = new Index('aaa', 23, 20000); var_dump($I->salary); //输出 20000 $test(); //输出 array(1) { ["Index"]=> string(11) "./Index.php" } ?>
使用spl_autoload_register的高级方式来完成类的加载,在后面的版本中autoLoad有可能会被弃用,但是目前autoLoad的使用范围还是很广泛
spl_autoload_register可以灵活的来注册需要加载的类,用法举例如下
<?php header('content-type:text/html;charset=utf8'); ini_set('display_errors', true); //指定的加载模块 spl_autoload_register('my_autoload_func'); /**自定义的自动加载函数 * @param $class_name */ function my_autoload_func($class_name) { var_dump(func_get_args()); //输出 array(1) { [0]=> string(5) "Index" } require_once "./{$class_name}.php"; } //会自动引进Index这个类 $p = new Index('leo', 30, 30000); var_dump($p->salary); //输出 int(30000) ?>