php基础复习

基础捡漏:

1、短标记<??> 通过修改ini文件的short_open_tag或编译时 --enable-short-tags 可用 不推荐使用、

2、?>默认有隐藏分号结束,而文件最后可以省略?>

3、使用条件的高级分离术

<?php if ($expression == true): ?>
  This will show if the expression is true.
<?php else: ?>
  Otherwise this will show.
<?php endif; ?>

!!后面的程序不执行了??

php解析器会在条件未达成时直接跳过该条件语句块??所以比echo、print更有效率

所以适用输出大段文本

4、script式

<script language="php">
        echo 'some editors (like FrontPage) don\'t
              like processing instructions';
    </script>

好像没什么意义阿,又输出不出来

5、自 PHP 5.4 起,短格式的 echo 标记 <?= 总会被识别并且合法,而不管 short_open_tag 的设置是什么。所以1不成立

6、9种原始数据类型

标量类型

boolean

integer

float

string

复合类型
array

object

Callback/Callable(可调用)??与类有关

特殊类型

resource(资源)

NULL(无类型)

为了确保代码的易读性,本手册还介绍了一些伪类型://就是实际没有这种类型

mixed(混合类型)
number(数字类型)
callback(回调类型,又称为 callable)
array|object(数组 | 对象类型)
void (无类型)

 7、php是弱类型语言,所以php根据变量的上下文来判断变量的类型;

查看变量的值和类型:var_dump();

输出类型:gettype();

判断是否是某类型:is_int/string/object()

8、变量强制转换为某类型

(boolean/bool) $foo

settype($a, 'string');//返回true/false

9、echo(false);为空白!

10、类型比较表,https://www.php.net/manual/zh/types.comparisons.php 比较很特殊的值

11、空数组转换为boolean时,为false,变量在流程控制中if($a),自动转化为boolean类型

12、整数:要使用八进制表达,数字前必须加上 0(零)。要使用十六进制表达,数字前必须加上 0x。要使用二进制表达,数字前必须加上 0b

13、整数是有符号的,整数的最大最小值与系统有关,32位,0/1 (符号位)31个1 所以是2^31-1 (二进制计算哟) 2147483647

同理64位系统,则是2^63-1 为9223372036854775807

超过这两个数,则将转化成float类型

14、强制转化为整形 

(int) 或 (integer) 

intval($非object,0/10/2/8/16)  object会报错,后面参数为什么进制,如果是0,则根据变量本身来判断

成功时返回 var 的 integer 值,失败时返回 0。 空的 array 返回 0,非空的 array 返回 1

 15、浮点数的精度有限。尽管取决于系统,PHP通常使用IEEE 754双精度格式(64位),永远不要相信浮点数结果精确到了最后一位,也永远不要比较两个浮点数是否相等

16、计算浮点数相等的例子

<?php
$a = 1.23456789;
$b = 1.23456780;
$epsilon = 0.00001;

if(abs($a-$b) < $epsilon) {
    echo "true";
}
?>

17、NAN  is_nan()

18、每个字符等同于一个字节。这意味着 PHP 只能支持 256 的字符集,因此不支持 Unicode,最大可达2GB

19、四种表达方式

  单引号

  双引号

  heredoc 语法结构

  nowdoc 语法结构

 20、单引号除\' \\外 其他\转义均无效

21、\[0-7]{1,3} 符合该正则表达式序列的是一个以八进制方式来表达的字符

\x[0-9A-Fa-f]{1,2} 符合该正则表达式序列的是一个以十六进制方式来表达的字符

不太明白

22、heredoc 句法结构:<<<

$str = <<<EOD
Example of string
spanning multiple lines
using heredoc syntax.
EOD;

EOD是遵守 PHP 的规则:只能包含字母、数字和下划线,并且必须以字母和下划线作为开头。

echo <<<EOT
My name is "$name". I am printing some $foo->foo.
Now, I am printing some {$foo->bar[1]}.
This should print a capital 'A': \x41
EOT;

里面可以包含变量

Heredoc 结构还可以来初始化静态变量和类的属性和常量

或者

$str = <<<“EOD”
Example of string
spanning multiple lines
using heredoc syntax.
EOD;

23、Nowdoc 结构

$str = <<<‘EOD’
Example of string
spanning multiple lines
using heredoc syntax.
EOD;

里面纯文本,不解析,类似单引号

 24、当 PHP 解析器遇到一个美元符号($)时,它会和其它很多解析器一样,去组合尽量多的标识以形成一个合法的变量名。可以用花括号来明确变量名的界线。一个 array 索引或一个 object 属性也可被解析

// Invalid. "s" is a valid character for a variable name, but the variable is $juice.
echo "He drank some juice made of $juices.";

He drank some juice made of .
echo "He drank some $juices[0] juice.".PHP_EOL;
echo "$people->john drank some $juices[0] juice.".PHP_EOL;

25、php换行符PHP_EOL,以提高代码的源代码级可移植性

 26、变量解析复杂模式(花括号)

{$} $必须和{紧挨着

// 有效,只有通过花括号语法才能正确解析带引号的键名
echo "This works: {$arr['key']}";

// 有效,输出: This is fantastic

echo "This is ${great}";

echo "This is the value of the var named by the return value of getName(): {${getName()}}";

// 无效,输出: This is the return value of getName(): {getName()}
echo "This is the return value of getName(): {getName()}"

<?php

class beers {
    const softdrink = 'rootbeer';
    public static $ale = 'ipa';
}

$rootbeer = 'A & W';
$ipa = 'Alexander Keith\'s';

// 有效,输出: I'd like an A & W
echo "I'd like an {${beers::softdrink}}\n";

// 也有效,输出: I'd like an Alexander Keith's
echo "I'd like an {${beers::$ale}}\n";

总结:复杂的起始{${ 表达式,可以是类的变量或者函数}}

27、string 中的字符可以通过一个从 0 开始的下标 类似array

// 取得字符串的第一个字符
$str = 'This is a test.';
$first = $str[0];

string 也可用花括号访问,比如 $str{42}

用超出字符串长度的下标写入将会拉长该字符串并以空格填充,非整数的下标将会转成整数

28、substr(string $string, int $start[, int $length]) : string

length 和 start 可为负 从末尾开始算

substr_replace( mixed $string , mixed $replacement , mixed $start [, mixed $length ] ) : mixed)

 length 和 start 可为负 从末尾开始算

29、(string)$var 和 strval() 不能将 strval() 用于数组或对象

30、一个布尔值 boolean 的 TRUE 被转换成 string 的 "1"。Boolean 的 FALSE 被转换成 ""(空字符串)

 31、获取类的名称

get_class($object) 和 __toString()

32、大部分的 PHP 值可以转变成 string 来永久保存,这被称作串行化

serialize() 返回字符串,此字符串包含了表示 value 的字节流,可以存储于任何地方。

这有利于存储或传递 PHP 的值,同时不丢失其类型和结构。

想要将已序列化的字符串变回 PHP 的值,可使用 unserialize()

[1,2,3,4] => string(38) "a:4:{i:0;i:1;i:1;i:2;i:2;i:3;i:3;i:4;}"

33、字符串转数值

$foo = 1 + "10.5";                // $foo is float (11.5)
$foo = 1 + "-1.3e3";              // $foo is float (-1299)
$foo = 1 + "bob-1.3e3";           // $foo is integer (1)
$foo = 1 + "bob3";                // $foo is integer (1)
$foo = 1 + "10 Small Pigs";       // $foo is integer (11)
$foo = 4 + "10.2 Little Piggies"; // $foo is float (14.2)
$foo = "10.0 pigs " + 1;          // $foo is float (11)
$foo = "10.0 pigs " + 1.0;        // $foo is float (11) 

33、ord() 查字符的ascii吗

chr()反过来

34、字符串类型详解

 

PHP 中的 string 的实现方式是一个由字节组成的数组再加上一个整数指明缓冲区长度

NUL 和 NULL

Bin
(二进制)
Oct
(八进制)
Dec
(十进制)
Hex
(十六进制)
缩写/字符
解释
0000 0000
00
0
0x00
NUL(null)
空字符
0000 0001
01
1
0x01
SOH(start of headline)
标题开始
0000 0010
02
2
0x02
STX (start of text)
正文开始

一个‘L’的NUL用于结束一个ASCII字符串,

两个‘L’的NULL用于表示什么也不指向(空指针)

字符串类型的此特性解释了为什么 PHP 中没有单独的“byte”类型 - 已经用字符串来代替了

35、栈(stack)又名堆栈,

它是一种运算受限的线性表。其限制是仅允许在表的一端进行插入和删除运算。这一端被称为栈顶,相对地,把另一端称为栈底。向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素

36、数组

PHP 中的数组实际上是一个有序映射。映射是一种把 values 关联到 keys 的类型。

key 为整数或者字符串

5.4起 可[]定义

布尔值也会被转换成整型。即键名 true 实际会被储存为 1 而键名 false 会被储存为 0。

 Null 会被转换为空字符串,即键名 null 实际会被储存为 ""。

 亦可用花括号来访问  $array[42] 和 $array{42} $array{“a”}

 37、5.4之前不能进行数组解引用

 <?php
function getArray() {
    return array(1, 2, 3);
}

// on PHP 5.4
$secondElement = getArray()[1];

// previously
$tmp = getArray();
$secondElement = $tmp[1];

// or
list(, $secondElement) = getArray();

list()为一个语言结构,将数组按顺序赋值于变量,7.1.0之后可以用于字符串数组,方向从左到右

38、$arr[] = value;加在末尾

39、删除某键值

unset($arr[5]);

40、array_values ()

返回所有的值,并重建数字索引

$array = array("size" => "XL", "color" => "gold");
print_r(array_values($array));

Array
(
[0] => XL
[1] => gold
)

41、注意这里所使用的最大整数键名不一定当前就在数组中。它只要在上次数组重新生成索引后曾经存在过就行了

比如unset数组的所有元素,但是索引的排序一直都在

42、unset() 函数允许删除数组中的某个键。但要注意数组将不会重建索引

43、

$foo[bar] = 'enemy';
echo $foo[bar];

如之前无常量bar,则php自动转为'bar'; but

this will throw an Error in a future version of PHP

44、尽量不要用常量来做key,因为常量可能随着版本变化而变化,保留字也是一样的

45、转化为数组

(array)$var $var如果是除对象和数组外其他类型,则转为一个只有0索引的数组

null将转成一个空数组

 46、对象转成数组

 其单元为该对象的属性。键名将为成员变量名,不过有几点例外:整数属性不可访问;私有变量前会加上类名作前缀;保护变量前会加上一个 '*' 做前缀。这些前缀的前后都各有一个 NULL 字符。

class A {
private $A=1; // This will become '\0A\0A'
}

class B extends A {
private $A=2; // This will become '\0B\0A'
public $AA=3; // This will become 'AA'

protected $AAA=4;
}

var_dump((array) new B());

array(3) { ["BA"]=> int(2) ["AA"]=> int(3) ["*AAA"]=> int(4)  ["AA"]=> int(1) } 后面的AA 其实是'\0A\0A';

类中函数将会被忽视

47、比较数组

arr_diff(很多array) 返回在第一个数组中但是不在其他 array 里的值

$a = array("a" => "apple", "b" => "banana");
$b = array("a" => "pear", "b" => "strawberry", "c" => "cherry");

$c = $a + $b; // 谁在前,以谁为尊

array(3) {
["a"]=>
string(5) "apple"
["b"]=>
string(6) "banana"
["c"]=>
string(6) "cherry"
}
$c = $b + $a;

array(3) {
["a"]=>
string(4) "pear"
["b"]=>
string(10) "strawberry"
["c"]=>
string(6) "cherry"
}

48、数组传引用,直接改数组值

$colors = array('red', 'blue', 'green', 'yellow');
foreach ($colors as &$color) {
$color = strtoupper($color);
}
var_dump($colors);

array(4) { [0]=> string(3) "RED" [1]=> string(4) "BLUE" [2]=> string(5) "GREEN" [3]=> &string(6) "YELLOW" }之前认为&为bug

//去掉引用关系unset

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

$index = 1;
foreach ($colors as &$color) {
$color = strtoupper($color);
if($index == 4)
unset($color);
$index++;
}
var_dump($colors);

在打印之前unset($color),则会解决这个bug

49、填充数组

$handle = opendir('.');//打开读取,关闭,并将文件名写入一个数组
while (false !== ($file = readdir($handle))) {
    $files[] = $file;
}
closedir($handle);

50、数组(Array) 的赋值总是会涉及到值的拷贝。使用引用运算符通过引用来拷贝数组。

$arr1 = array(2, 3);
$arr2 = $arr1;
$arr2[] = 4; // $arr2 is changed,
             // $arr1 is still array(2, 3)
             
$arr3 = &$arr1;
$arr3[] = 4; // now $arr1 and $arr3 are the same

51、对象

要创建一个新的对象 object,使用 new 语句实例化一个类。

52、转化为对象

除数组外,如果其它任何类型的值被转换成对象,将会创建一个内置类 stdClass 的实例

var_dump((object)NULL);
var_dump((object)"abc");

object(stdClass)#1 (0) { }

object(stdClass)#1 (1) { ["scalar"]=> string(3) "abc" }

数组转对象

var_dump((object) array('1' => 'foo'));

object(stdClass)#1 (1) { ["1"]=> string(3) "foo" }

$obj = (object) array('1' => 'foo');
var_dump(isset($obj->{'1'}));//注意花括号的使用

 53、资源 resource 是一种特殊变量,保存了到外部资源的一个引用

54、null类型 只有一个值null 特殊的 NULL 值表示一个变量没有值

三种情况认定为null

被赋值为 NULL。

尚未被赋值。

被 unset()。

55、转换为null值

使用 (unset) $var 将一个变量转换为 null 将不会删除该变量或 unset 其值。仅是返回 NULL 值而已。

$a = 123;
var_dump((unset)$a);
var_dump($a);

NULL

int(123)

56、call_user_func(funcname, argu1,argu2),把第一个参数作为回调函数调用,后续为该函数的参数,而funcname则为callback类型,实际上是以string形式传递的

请注意,传入call_user_func()的参数不能为引用传递!!

function increment () {
    global $a;
    $a ++;
}

$a = 0;

call_user_func('increment', $a);

var_dump($a);

call_user_func_array('increment', [$a]);

var_dump($a);

57、usort — 使用用户自定义的比较函数对数组中的值进行排序

usort(array &arr, callback): bool

在第一个参数小于,等于或大于第二个参数时,该比较函数必须相应地返回一个小于,等于或大于 0 的整数

callback($a, $b): int 

57、Callback / Callable 类型

自 PHP 5.4 起可用 callable 类型指定回调类型 callback

callback 可以使用任何内置或用户自定义的函数,还可以是对象的方法,包括静态类方法,但除了语言结构外

当时对象的方法时,用array做参数

// An example callback method
class MyClass {
    static function myCallbackMethod() {
        echo 'Hello World!';
    }
}

// Type 3: Object method call
$obj = new MyClass();
call_user_func(array($obj, 'myCallbackMethod'));

// Type 4: Static class method call (As of PHP 5.2.3)
call_user_func('MyClass::myCallbackMethod');

class A {
    public static function who() {
        echo "A\n";
    }
}

class B extends A {
    public static function who() {
        echo "B\n";
    }
}

call_user_func(array('B', 'parent::who')); // A

 // Type 6: Objects implementing __invoke can be used as callables (since PHP 5.3)
class C {
    public function __invoke($name) {
        echo 'Hello ', $name, "\n";
    }
}

$c = new C();
call_user_func($c, 'PHP!');

58、魔术函数__invoke

当尝试以调用函数的方式调用一个对象时,__invoke() 方法会被自动调用

class CallableClass 
{
    function __invoke($x) {
        var_dump($x);
    }
}
$obj = new CallableClass;
$obj(5);//把object当成函数使用,invoke就被调用了
var_dump(is_callable($obj)); //true

is_callable() 函数用于检测函数在当前环境中是否可调用

59、range()函数

创建一个包含从 "0" 到 "5" 之间的元素范围的数组

$number = range(0,5);
print_r ($number);

60、Closure 闭包

闭包就是能够读取其他函数内部变量的函数,所以闭包可以理解成“定义在一个函数内部的函数“。在本质上,闭包是将函数内部和函数外部连接起来的桥梁。

// Our closure
$double = function($a) {
    return $a * 2;
};

// This is our range of numbers
$numbers = range(1, 5);

// Use the closure as a callback here to 
// double the size of each element in our 
// range
$new_numbers = array_map($double, $numbers);//array_map:函数将用户自定义函数作用到数组中的每个值上,并返回用户自定义函数作用后的带有新值的数组

print implode(' ', $new_numbers);

61、call_user_func_array(callable $callback , array $param_arr ) : mixed

第一个参数为回调函数,后面的数组依次为他的参数,如果出错的话返回false

function foobar($arg, $arg2) {
    echo __FUNCTION__, " got $arg and $arg2\n";
}
class foo {
    function bar($arg, $arg2) {
        echo __METHOD__, " got $arg and $arg2\n";
    }
}


// Call the foobar() function with 2 arguments
call_user_func_array("foobar", array("one", "two"));

// Call the $foo->bar() method with 2 arguments
$foo = new foo;
call_user_func_array(array($foo, "bar"), array("three", "four"));//第一个array表示调用$foo实例的bar函数,第二个表示为bar函数的依次参数

 如果有命名空间时,调用

namespace Foobar;

class Foo {
    static public function test($name) {
        print "Hello {$name}!\n";
    }
}

// 大于PHP 5.3.0
call_user_func_array(__NAMESPACE__ .'\Foo::test', array('Hannes'));//静态函数简便调用

// PHP 5.3.0 之前
call_user_func_array(array(__NAMESPACE__ .'\Foo', 'test'), array('Philip'));

//传引用

function mega(&$a){//&5.4以前可省略,后不行,还是写完整
    $a = 55;
    echo "function mega \$a=$a\n";
}
$bar = 77;
call_user_func_array('mega',array(&$bar));
echo "global \$bar=$bar\n";

function mega $a=55
global $bar=55 //引用生效

 62、在函数中注册有多个回调内容时(如使用 call_user_func() 与 call_user_func_array()),如在前一个回调中有未捕获的异常,其后的将不再被调用

63、伪类

number 说明一个参数可以是 integer 或者 float

void 作为返回类型意味着函数的返回值是无用的。void 作为参数列表意味着函数不接受任何参数。

在函数原型中,$... 表示等等的意思。当一个函数可以接受任意个参数时使用此变量名。

64、类型转换

允许的强制转换有:

(int), (integer) - 转换为整形 integer
(bool), (boolean) - 转换为布尔类型 boolean
(float), (double), (real) - 转换为浮点型 float
(string) - 转换为字符串 string
(array) - 转换为数组 array
(object) - 转换为对象 object
(unset) - 转换为 NULL (PHP 5)

$binary = (binary)$string;
$binary = b"binary string";//转化为二进制字符串(php5.2 +)

$avar = "中国";

var_dump((binary)$avar);
var_dump(b"$avar");

string(6) "中国" string(6) "中国" //??啥意思 不是二进制??

65、变量语法

$

区分大小写,字母或下划线开头,后面任意数量的字母数字下划线

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

$i站点is = 'mansikka';  // 合法变量名;可以用中文

66、以下代码结构会进入全局命名空间:

functions(函数)

classes (类)

interfaces(接口)

constants (常量,非类常量)

在函数/方法之外定义的变量


function yy(){
define('XX','xxx');
$xx = 'xyz';
}
yy();
var_dump(XX);
var_dump($xx);

  string(3) "xxx"

NULL

要写出能经受住时间考验的代码,建议给任何进入全局命名空间的符号都加上一个不常见的 3-4 字母的前缀(或后缀),中间用下划线分开。为了避免与其它用户空间代码出现命名空间冲突,建议先研究一下其它项目中已有的前缀(或后缀)并适当地公布出来。示例如下

MyPx_someFunc()

Foo_Date

$asdf_dbh

约定

函数名在两个词中间使用下划线 例如curl_close

类名则使用camelCase 或 PascalCase

__魔术变量,不要用__开头的符号

Iterators 和 Exceptions ?? 迭代器和异常??

 67、变量默认值

未初始化的变量具有其类型的默认值 - 布尔类型的变量默认值是 FALSE,整形和浮点型变量默认值是零,字符串型变量(例如用于 echo 中)默认值是空字符串以及数组变量的默认值是空数组。

isset() 语言结构可以用来检测一个变量是否已被初始化

// String usage; outputs 'string(3) "abc"'
$unset_str .= 'abc';
var_dump($unset_str);

// Object usage; creates new stdClass object (see http://www.php.net/manual/en/reserved.classes.php)
// Outputs: object(stdClass)#1 (1) {  ["foo"]=>  string(3) "bar" }
$unset_obj->foo = 'bar';
var_dump($unset_obj);

68、如果register_globals值为false,PHP5.4已剔除这个

为了得到 DOCUMENT_ROOT 的值,将必须使用$_SERVER['DOCUMENT_ROOT'] 代替 $DOCUMENT_ROOT,又如,使用 $_GET['id'] 来代替 $id

69、预定义变量

1、超全局变量

$GLOBALS --引用全局作用域中可用的全部变量
$_SERVER
$_GET
$_POST
$_FILES
$_COOKIE
$_SESSION
$_REQUEST
$_ENV //环境变量

2、其他预定义变量

$_COOKIE — HTTP Cookies
$php_errormsg — 前一个错误信息
$HTTP_RAW_POST_DATA — 原生POST数据
$http_response_header — HTTP 响应头
$argc — 传递给脚本的参数数目
$argv — 传递给脚本的参数数组

70、获取原生POST数据

$HTTP_RAW_POST_DATA 一般而言,使用php://input 代替

php:// — 访问各个输入/输出流

71、函数中不可直接使用全局变量,要访问有两个方法

1、加一个global 的关键字

2、$GLOBALS['b'] 使用超全局变量

注意其他预定义变量 不是超全局 所以还是需要global关键字 如$HTTP_RAW_POST_DATA

72、静态变量 

关键字 static 

静态变量仅在局部函数域中存在,但当程序执行离开此作用域时,其值并不丢失,相当于只运行一次

function test()
{
    static $a = 0;
    echo $a;
    $a++;
}//使用递归,以前开发都是传参数进去,原来有更方便的static关键字

其实放在全局空间内,并没有报错,但是无意义

注意:static 赋值时不能用表达式

static $a = 1+1; //错误

 73、Zend Engine 编译器和执行器

Zend Engine最主要的特性就是把PHP的边解释边执行的运行方式改为先进行预编译(Compile),然后再执行(Execute) 类似GCC

74、


function test_global_ref() {
global $obj;
$obj = &new stdclass;//这个php7.2会报语法错误
}

function test_global_noref() {
global $obj;
$obj = new stdclass;//正确用法
}

test_global_ref();
var_dump($obj);
test_global_noref();
var_dump($obj);

75、引用:用两个变量来指向同一个内容,指向了同一个地方

75.1、引用是什么

在 PHP 中引用意味着用不同的名字访问同一个变量内容,变量名和变量内容是不一样的, 因此同样的内容可以有不同的名字。引用可以被看作是 Unix 文件系统中的硬链接。参见76

 75.2、引用做什么

第一件事:PHP 的引用允许用两个变量来指向同一个内容

(1)、如果对一个未定义的变量进行引用赋值、引用参数传递或引用返回,则会自动创建该变量。

<?php
function foo(&$var) { }

foo($a); // $a is "created" and assigned to null

$b = array();
foo($b['b']);
var_dump(array_key_exists('b', $b)); // bool(true)

$c = new StdClass;
foo($c->d);
var_dump(property_exists($c, 'd')); // bool(true)

(2)、同样的语法可以用在函数中,它返回引用,以及用在 new 运算符中(自 PHP 5 起,new 自动返回对象的引用)

$bar =& new fooclass();// php5 之后会报错
$foo =& find_var($bar);

(3)、如果在一个函数内部给一个声明为 global 的变量赋于一个引用,该引用只在函数内部可见。可以通过使用 $GLOBALS 数组避免这一点。

$a = 123;
$b = 456;
function a(){
global $a,$b;
$a = &$b;或$GLOBALS["a"] = &$b;
echo $a;
}
a();//456 或123
echo $a;//123 或456

把 global $var; 当成是 $var =& $GLOBALS['var']; 的简写。从而将其它引用赋给 $var 只改变了本地变量的引用。

第二件事:引用做的第二件事是用引用传递变量

可以将一个变量通过引用传递给函数,这样该函数就可以修改其参数的值

function foo(&$var)//注意在函数调用时没有引用符号——只有函数定义中有,光是函数定义就足够使参数通过引用来正确传递了
{
    $var++;
}

$a=5;
foo($a);

三种情况可以通过引用传递

变量,例如 foo($a)

New 语句,例如 foo(new foobar())

从函数中返回的引用,例如:

function &bar()
{
    $a = 5;
    return $a;
}
foo(bar());//相见引用返回

任何其它表达式都不能通过引用传递

第三件事:引用做的第三件事是引用返回

 定义:用在当想用函数找到引用应该被绑定在哪一个变量上面时

不要用返回引用来增加性能,引擎足够聪明来自己进行优化。仅在有合理的技术原因时才返回引用

class foo {
    public $value = 42;

    public function &getValue() {
        return $this->value;
    }
}

$obj = new foo;
$myValue = &$obj->getValue(); // $myValue is a reference to $obj->value, which is 42.
$obj->value = 2;
echo $myValue;                // prints the new value of $obj->value, i.e. 2.

//和参数传递不同,这里必须在两个地方都用 & 符号——指出返回的是一个引用,而不是通常的一个拷贝,同样也指出 $myValue 是作为引用的绑定,而不是通常的赋值。

75.3、引用不是什么

引用不是指针

function foo(&$var)
{
    $var =& $GLOBALS["baz"];
}
foo($bar);

var只能更改baz,不能更改bar;

75.3、取消引用

当 unset 一个引用,只是断开了变量名和变量内容之间的绑定。这并不意味着变量内容被销毁了

75.4、引用定位

许多 PHP 的语法结构是通过引用机制实现的

当用 global $var 声明一个变量时实际上建立了一个到全局变量的引用,等于$var =& $GLOBALS["var"];

在一个对象的方法中,$this 永远是调用它的对象的引用

76、unix文件系统中的硬链接和软连接 

 
 
 
 
 
 
 
 

硬链接:

一般情况下,文件名和inode号码是"一一对应"关系,每个inode号码对应一个文件名。但是,Unix/Linux系统允许,多个文件名指向同一个inode号码。

这意味着,可以用不同的文件名访问同样的内容;对文件内容进行修改,会影响到所有文件名;但是,删除一个文件名,不影响另一个文件名的访问。这种情况就被称为"硬链接"(hard link)。

共用同一个索引的许多不同名文件,修改一个文件会影响所有其他的文件,但是删除单个文件其他文件依然存在,只有在所有硬链接连接的文件都被删除之后,inode才会被释放。

软连接:

文件A和文件B的inode号码虽然不一样,但是文件A的内容是文件B的路径。读取文件A时,系统会自动将访问者导向文件B。因此,无论打开哪一个文件,最终读取的都是文件B。这时,文件A就称为文件B的"软链接"(soft link)或者"符号链接(symbolic link)。

这意味着,文件A依赖于文件B而存在,如果删除了文件B,打开文件A就会报错:"No such file or directory"。这是软链接与硬链接最大的不同:文件A指向文件B的文件名,而不是文件B的inode号码,文件B的inode"链接数"不会因此发生变化。

77、可变变量

$a = 'Hello';

$$a = 'World';

用于数组$$a[1],摸棱两可

${$a[1]}:$a[1]作为变量

${$a}[1]:$$a作为变量,并取出索引1

类中数组属性:

$fool->$arr[1]:先计算数组值,再取属性

$fool->{$arr}[1]:先取属性,再取数组值

超全局变量和$this不能作为可变变量使用

78、来自php之外的变量

 POST/GET html表单访问数据

$_POST

$_REQUEST  //默认情况下包含了 $_GET$_POST 和 $_COOKIE 的数组

$_GET

将 GET/POST/Cookie 变量导入到全局作用域中

import_request_variables('p or g or c', 'ud_'): bool //p代表post,g代表get,c代表cookie,ud_代表给变量加前缀

如果 PHP 指令 register_globals = on

html提交的变量自动导入到全局作用域,用import_request_variables更好

变量名中的点和空格被转换成下划线。例如 <input name="a.b" /> 变成了 $_REQUEST["a_b"] //所以尽量规范表单中命名

79、magic_quotes_gpc(php5.4-)配置将会把输入的值先addslashes(),

addslashes()//该字符串为了数据库查询语句等的需要在某些字符前加上了反斜线。这些字符是单引号(')、双引号(")、反斜线(\)与 NUL(NULL 字符)

stripslashes()//正好相反效果

80、<input type="text" name="personal[name]"><br />
    <input type="text" name="personal[email]"><br /> 这样传到后端也是一个数组

81、<input type="image" src="image.gif" name="sub" /> 点击就图片就会上传 sub.x sub.y 传到后台将变成sub_x sub_y

82、http cookies

Cookies 是一种在远端浏览器端存储数据并能追踪或识别再次访问的用户的机制

Cookies 是 HTTP 信息头中的一部分,因此 SetCookie 函数必须在向浏览器发送任何输出之前调用

一旦设置 Cookie 后,下次打开页面时可以使用 $_COOKIE,$HTTP_COOKIE_VARS 和 $_REQUEST 读取

如果想在仅仅一个 cookie 中设定多个值,考虑先在值上使用serialize() 或 explode() ??应该是implode()吧

83、常量

 在脚本执行期间该值不能改变,常量默认为大小写敏感。传统上常量标识符总是大写的

合法的常量名以字母或下划线开始,后面跟着任何字母,数字或下划线

应该避免这样做:(自定义常量不要以__开头),和魔术常量冲突

不用管作用区域就可以在脚本的任何地方访问常量 在函数内也能全局?

84、表达式

表达式是 PHP 最重要的基石。在 PHP 中,几乎所写的任何东西都是一个表达式。简单但却最精确的定义一个表达式的方式就是“任何有值的东西”

因为赋值操作的顺序是由右到左的 $b = $a =5

85、前后递增

$a = ++$b,前递增,写做“++$variable”,求增加后的值(PHP 在读取变量的值之前,增加变量的值,因而称之为“前递增”)。

$a = $b++,后递增,写做“$variable++”,求变量未递增之前的原始值(PHP 在读取变量的值之后,增加变量的值,因而叫做“后递增”)

86、组合的运算赋值表达式

$a += 3

任何二元运算符都可以用运算赋值模式,例如“$a -= 5”(从变量 $a 的值中减去 5),“$b *= 7”

87、语句

一条语句等于表达式(expr )加分号结尾

88、运算符

运算符可按照其能接受几个值来分组。一元运算符只能接受一个值,二元运算符可接受两个值,三元运算符

三元条件运算符:$first ? $second : $third

89、运算符优先级

如果优先级相同,那运算服结合方向决定改如何运算

https://www.php.net/manual/zh/language.operators.precedence.php

90、算术运算符

$a**$b 乘方 php5.6+ a的b次方

除法运算符总是返回浮点数

取模运算符的操作数在运算之前都会转换成整数 %,取模运算符 % 的结果和被除数的符号(正负号)相同,即 $a % $b 的结果和 $a 的符号相同

91、赋值运算符

基本运算符 =

引用赋值

new 运算符自动返回一个引用 php5+

92、位运算 参见另一个随笔 https://www.cnblogs.com/ValleyUp/p/10950238.html

93、比较运算符

太空船比较符 $a<==>$b 当$a小于、等于、大于$b时 分别返回一个小于、等于、大于0的integer 值 php7+   -1 0 1

// Arrays
echo [] <=> []; // 0
echo [1, 2, 3] <=> [1, 2, 3]; // 0
echo [1, 2, 3] <=> []; // 1
echo [1, 2, 3] <=> [1, 2, 1]; // 1
echo [1, 2, 3] <=> [1, 2, 4]; // -1 一个一个比较

$a = (object) ["a" => "c"]; 
$b = (object) ["a" => "b"]; 
echo $a <=> $b; // 1
 
// 只比较值

$a = (object) ["a" => "b", "b" => "b"]; 
$b = (object) ["b" => "b", "a" => "a"];

先排序

  //abbb

  //aabb

然后比较,第二位分胜负
echo $a <=> $b; // 1

NULL 合并操作符 $a??$b 从左往右第一个存在且不为 NULL 的操作数。如果都没有定义且不为 NULL,则返回 NULL php7+

95、多种类型比较时

1、object>array>其他任何类型 

2、array间比较

  具有较少成员的数组较小,如果运算数 1 中的键不存在于运算数 2 中则数组,则运算数2比较大,否则挨个值比较

3、object间的比较 php5+

当使用比较运算符(==)比较两个对象变量时,比较的原则是:如果两个对象的属性和属性值 都相等,而且两个对象是同一个类的实例,那么这两个对象变量相等。

而如果使用全等运算符(===),这两个对象变量一定要指向某个类的同一个实例(即同一个对象)

94、Object of class stdClass could not be converted to string 内置stdClass类无法转成字符串
95、由于浮点数的内部表达方式,不应比较两个浮点数是否相等
96、三元运算符可省略中间那部分 表达式 expr1 ?: expr3 在 expr1 求值为 TRUE 时返回 expr1,否则返回 expr3 php5.3+
此表达式将返回第一个非false的值
echo 0?:0?:0?:0?:1?:0;//1
97、错误控制运算符@
将其放置在一个 PHP 表达式之前,该表达式可能产生的任何错误信息都被忽略掉
不能把它放在函数或类的定义之前,也不能用于条件结构例如 if 和 foreach 等,只能放在表达式中(如果能从某处得到值,就能在它前面加上 @ 运算符)
如果用 set_error_handler() 设定了自定义的错误处理函数,仍然会被调用,但是此错误处理函数可以(并且也应该)调用 error_reporting(),而该函数在出错语句前有 @ 时将返回 0, or die();
98、如果激活了 track_errors 特性,表达式所产生的任何错误信息都被存放在变量 $php_errormsg 中 

ini_set("track_errors", true);
printf(ini_get("track_errors"));

$file = @file('a.txt');

echo $php_errormsg;

99、自定义错误处理函数 set_error_handler(callback, 错误级别);

 1 function myErrorHandler($errno, $errstr, $errfile, $errline){//错误级别,整形; 错误字符串;错误文件名;错误所在行号
 2     //error_reporting的设置对此机制无效,或者通过@过来的错误也会调用,依旧会调用这个函数,
 3     //设定当当前错误不在设定的error_reporting级别时,函数不做处理
 4     if(!(error_reporting()& $errno))
 5         return false;//如返回false, error_types 里指定的错误类型都会绕过 PHP 标准错误处理程序, 除非回调函数返回了 FALSE
 6     switch ($errno) {
 7     case E_USER_ERROR:
 8         echo "<b>My ERROR</b> [$errno] $errstr<br />\n";
 9         echo "  Fatal errors on line $errline in file $errfile";
10         echo ", PHP " . PHP_VERSION . " (" . PHP_OS . ")<br />\n";
11         echo "Aborting...<br />\n";
12         exit(1);
13         break;
14 
15     case E_USER_WARNING:
16         echo "<b>My WARNING</b> [$errno] $errstr<br />\n";
17         break;
18 
19     case E_USER_NOTICE:
20         echo "<b>My NOTICE</b> [$errno] $errstr<br />\n";
21         break;
22     default:
23         echo "Unknown errors type: [$errno] $errstr<br />\n";
24         break;
25     }
26     //不执行默认处理函数
27     return true;
28 }
29 set_error_handler("myErrorHandler");
30 if(1==1){
31     trigger_error("测试错误", E_USER_ERROR);
32     //My ERROR [256] 测试错误
33     //Fatal errors on line 57 in file H:\mc\webroot\index.php, PHP 7.3.7 (WINNT)
34     //Aborting...
35 }

 

100、error_reporting();设置或返回错误级别

101、执行运算符`` PHP 将尝试将反引号中的内容作为 shell 命令来执行,并将其输出信息返回

102、递增/递减运算符不影响布尔值。递减 NULL 值也没有效果,但是递增 NULL 的结果是 1

1 $a = null;
2 $b = ++$a;
3 echo $b;//1

 103、逻辑运算符异或xor 一个为true 一个为false才为true

字符串运算符 .

104、数组运算符

$a + $b 联合 $a 和 $b 的联合。运算符把右边的数组元素附加到左边的数组后面,两个数组中都有的键名,则只用左边数组中的,右边的被忽略
$a == $b 相等 如果 $a 和 $b 具有相同的键/值对则为 TRUE
$a === $b 全等 如果 $a 和 $b 具有相同的键/值对并且顺序和类型都相同则为 TRUE

 105、类型运算符instanceof

继承类也是true

$a = (object)[1=>123, 0=>321];

echo $a instanceOf stdClass;//1

虽然 instanceof 通常直接与类名一起使用,但也可以使用对象或字符串变量

$c = "stdClass";

echo $a instanceOf $c;

$b = (object)[1,2,3];

echo $a instanceOf $b

106、do-while 保底运行一次

$i = 0;
do {
   echo $i;
} while ($i > 0);

107、for循环

for(;;;)表达式可以为空,可以用都好分开,判断第二个表达式时,只取最后一个的值

for ($i = 1; $i <= 10; print $i, $i++);//12345678910 省略打法

108、foreach

foreach 仅能够应用于数组和对象

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

养成习惯unset 最后一个value

$arr = array(1, 2);
foreach ($arr as &$value) {
    $value = $value * 2;
}
// $arr is now array(2, 4, 6, 8)
var_dump($arr);//array(2) { [0]=> int(2) [1]=> &int(4) }
unset($value); // 最后取消掉引用
var_dump($arr);//array(2) { [0]=> int(2) [1]=> int(4) }

109、嵌套数组用list解包

$arr = [[1,2],[3,4]];
foreach($arr as list($a, $b)){
    echo $a.PHP_EOL.$b.PHP_EOL;//1 2 3 4 
}

110、跳出循环或switch

break 结束当前 forforeachwhiledo-while 或者 switch 结构的执行

break 可以接受一个可选的数字参数来决定跳出几重循环

5.4.0 break 0; 不再合法。这在之前的版本被解析为 break 1;
5.4.0 取消变量作为参数传递(例如 $num = 2; break $num;

break 1 代笔推出当前循环或switch,以此类推

continue 在循环结构用用来跳过本次循环中剩余的代码并在条件求值为真时开始执行下一次循环,同样switch也可以用continue

5.4.0 continue 0; 不再合法。这在之前的版本被解析为 continue 1;
5.4.0 取消变量作为参数传递(例如 $num = 2; continue $num;)。

111、松散比较== 严格比较===

112、switch做松散比较,内部continue相当于break效果

switch比elseif更高效

允许使用分号代替 case 语句后的冒号

case 'tuborg';
case 'carlsberg';

113、流程控制的替代语法

 PHP 提供了一些流程控制的替代语法,包括 ifwhileforforeach 和 switch。替代语法的基本形式是把左花括号({)换成冒号(:),把右花括号(})分别换成 endif;endwhile;endfor;endforeach; 以及 endswitch;

 

$a=6;
if($a == 5):
    echo '5';
elseif($a == 6):
    echo '6';
else:
    echo 'else';
endif;
<?php $foo = 2?>
<?php switch ($foo): ?>
<?php case 1: ?>
    .(switch 和 case之间不能有其他html输出,空格也不行)
<?php case 2: ?>
    ..    
<?php endswitch ?>

114、declare ticks encoding

declare (directive)
statement
Tick(时钟周期)是一个在 declare 代码段中解释器每执行 N 条可计时的低级语句就会发生的事件。
不是所有语句都可计时。通常条件表达式和参数表达式都不可计时。

在每个 tick 中出现的事件是由 register_tick_function() 来指定的。

declare(ticks = 1);
function tick_handler(){
    global $a;
    echo "handler runs once $a</br>";
    $a++;
}
//函数register_tick_function注册时运行一次!!
register_tick_function('tick_handler');//handler runs once
$a = 1;//handler runs once 1

if ($a > 0) {
    
    $a += 2;//handler runs once 4
    
    echo ($a);//5handler runs once 5
    
}

 调用类中的函数

declare(ticks=1);
class TestDeclare{
    public function my_method($arg){
        echo $arg;
    }
}
$object = new TestDeclare();
register_tick_function([&$object, 'my_method'], 'test');
$a = 1;
$b = 2;

encording 可以用 encoding 指令来对每段脚本指定其编码方式

declare(encoding='ISO-8859-1');

115、return

1、函数内return,离开结束函数执行,并返回他的参数;

2、全局范围,中止当前脚本运行

echo 123;//123
return ;
echo 456;

include/require 返回值

a.php
<?php
include("b.php");
echo "a";
?>

b.php
<?php
echo "b";
return;
?>

include/require return之后的函数亦可搜索到

a.php 
<?php 
include 'b.php'; 

foo(); 
?> 

b.php 
<?php 
return; 

function foo() { 
     echo 'foo'; 
} 
?> 

116、绝对路径

在 Windows 下以盘符或者 \ 开头,在 Unix/Linux 下以 / 开头(撇捺Linux先行

117、include

php.ini 中include_path设置默认include的目录,如果没有给出目录,只有文件名,则按照这个路径去找,没找到的时候,才在当前的目录去找,所以为了提高效率,对于当前的路径,用.\(windows)前缀,..\代表父目录,以此类推,以绝对路径表示也是可以的。

函数内include的变量,作用域同函数内变量一致

function a(){
    require '.\inc.php'; 
    echo $a.$b;//12 作用于在函数内
}
a();
echo $a.$b;//null

php.ini 设置allow_url_include为On时,可include url文件,且为php文件后缀,且文件为php代码

处理返回值:在失败时 include 返回 FALSE 并且发出警告。成功的包含则返回 1,return 另说

// won't work, evaluated as include(('vars.php') == TRUE), i.e. include('')
if (include('inc.php') == TRUE) {
    echo 'OK';
}

// works
if ((include 'inc.php') == TRUE) {
    echo 'OK';
}
//include 不要用括号即可

另一个将 PHP 文件“包含”到一个变量中的方法是用输出控制函数结合 include 来捕获其输出

//index.php
function a($fileName){
    if(is_file($fileName)){
        ob_start();
        include $fileName;
        $contents = ob_get_contents();
        ob_end_clean();
        return $contents;
    }
    return false;
}
echo a('.\inc.php');//123
//inc.php
echo 123;

require和inlcude几乎完全相同,除了处理失败的方式不同之外。require 在出错时产生 E_COMPILE_ERROR 级别的错误。换句话说将导致脚本中止而 include 只产生警告(E_WARNING),脚本会继续运行。require严父啊

118、goto操作符 php5.3+

可以用来跳转到程序中的另一位置,该目标位置可以用目标名称加上冒号来标记

goto a;
echo 123;//跳过不执行
a:
echo 456;//456

目标位置只能位于同一个文件和作用域;

无法跳入到任何循环或者 switch 结构中。可以跳出循环或者 switch,通常的用法是用 goto 代替多层的 break

for($i = 0, $j = 50; $i < 100; $i++){
    while($j--){
        if($j==48) goto a;
    }
}
echo '123';
a:
echo 'j hits 48';

 

119、换行\r\n,必须在双引号中,且web前端看不出换行,源代码处换行,web换行用</br>

 120、引用

//变量引用
$a = 1;
$b = &$a;
$c = &$b;
$c = 2;
echo $a;//2
//引用传递
//1、函数的引用传递
function a(&$a){
    $a++;
}
$d = 3;
a($d);
echo $d;//4
//2、对象的引用传递,对象的实例化通过引用实现
class A{
    var $a = '123';
}
$e = new a();
$f = $e;
$f->a = '456';
echo $e->a;//456
//global 相当于引用全局变量,只在函数内部有效
//把 global $var; 当成是 $var =& $GLOBALS['var'],从而将其它引用赋给 $var 只改变了本地变量的引用
$a = 123;
$b = 456;
function c(){
    global $a,$b;
    $a = &$b;//或$GLOBALS["a"] = &$b;
    echo $a;
}
c();//456 或123
echo $a;//123 或456
//引用返回
function &b(){
    static $b = 0;//static 静态变量仅在局部函数域中存在,只执行一次
    $b++;
    echo $b;
    return $b;
}
$g = &b();//1
$g = 5;
b();//6

 121、函数

用户自定义函数

函数名和 PHP 中的其它标识符命名规则相同。有效的函数名以字母或下划线打头,后面跟字母,数字或下划线

任何有效的 PHP 代码都有可能出现在函数内部,甚至包括其它函数和定义

a();//可全局搜索a func
b();//当fun a 运行后,fun b已定义,所以此时可以调用
function a(){        
    function b(){
        echo 123;
    }
    b();//只能放在定义后面,放在前面则找不到函数
}

条件式

$makefoo = true;

/* 不能在此处调用foo()函数,
   因为它还不存在,但可以调用bar()函数。*/

bar();

if ($makefoo) {
  function foo()
  {
    echo "I don't exist until program execution reaches me.\n";
  }
}

/* 现在可以安全调用函数 foo()了,
   因为 $makefoo 值为真 */

if ($makefoo) foo();

function bar()
{
  echo "I exist immediately upon program start.\n";
}

PHP 中的所有函数和类都具有全局作用域,可以定义在一个函数之内而在之外调用,反之亦然

PHP 不支持函数重载,也不可能取消定义或者重定义已声明的函数

函数的参数

传参的三种方式

1、按值传递参数

2、通过引用传递参数

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

3、默认参数

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

function a($c, $b = 'abc', $a = 'hij'){//默认要放在最右边
    echo $c.$b.$a;
}
a('123');//123abchij
a('123', 'efg');//123efghij

参数的类型申明(类型提示)

类型声明允许函数在调用时要求参数为特定类型。 如果给出的值类型不对,那么将会产生一个错误: 在PHP 5中,这将是一个可恢复的致命错误,而在PHP 7中将会抛出一个TypeError异常

 

Class/interface name The parameter must be an instanceof the given class or interface name.//类或接口  PHP 5.0.0
self The parameter must be an instanceof the same class as the one the method is defined on. This can only be used on class and instance methods. PHP 5.0.0
array The parameter must be an array. PHP 5.1.0
callable The parameter must be a valid callable. PHP 5.4.0
bool The parameter must be a boolean value. PHP 7.0.0
float The parameter must be a floating point number. PHP 7.0.0
int The parameter must be an integer. PHP 7.0.0
string The parameter must be a string. PHP 7.0.0

不是正确的类型都将看作为类或接口,所以要写正确的bool,而boolean将视为类

function a($a, $b){
     return $a<=>$b;
 }
 function test(callable $param, int $a, int $b = 2) {
     return $param($a, $b);
 }
 echo test("a", 1);//-1

类继承

class C {}
class D extends C {}//继承于C

// 没有继承C
class E {}

function f(C $c) {
    echo get_class($c)."\n";
}

f(new C);//C
f(new D);//D
f(new E);//报错

接口实现

interface I { public function f(); }
class C implements I { public function f() {} }//实现接口I

//未实现接口I
class E {}

function f(I $i) {
    echo get_class($i)."\n";
}

f(new C);//C
f(new E);//报错

允许传递null,设置默认值为null即可

class C {}

function f(C $c = null) {
    var_dump($c);
}

f(new C);
f(null);

默认情况下,如果能做到的话,PHP将会强迫错误类型的值转为函数期望的标量类型

function b(string $a){//强迫自动转为string
    echo $a;
}
b(123);//123

严格模式

declare(strict_types = 1);//开启严格模式
function a(float $a){//唯一的一个例外是可以将integer传给一个期望float的函数。
    echo $a;
}
a(123);//123

function b(string $a){
    echo $a;
}
b(123);//报错

 可变数量的参数

php5.5之前,通过func_num_args()func_get_arg(),和 func_get_args() 

php5.6+,由由 ... 语法实现

通过...获取可变参数

function a(&...$a){
    foreach($a as &$val){
        $val += 1;
    }
}
$a = 1;
$b = 2;
a($a, $b);
echo $a,$b;//23

通过...提供可变参数

function a($a, $b){
    return $a+$b;
}
echo a(...[1,2]);//3
$a = [1,2];
echo a(...$a);//3

结合类型申明

function a($a = 1, int ...$b){
    foreach($b as $val){
        $a += $val;
    }
    return $a;
}
echo a(2,2,2);//6

返回值

参见return,如无return,则返回值为null

从函数返回一个引用,必须在函数声明和指派返回值给一个变量时都使用引用运算符 &

不要问为什么,这是规定

function &returns_reference()
{
    return $someref;
}

$newref =& returns_reference();

返回值的类型声明 php7+

支持类型与参数的相同,严格类型也同样影响

function sum($a, $b): float{
    return $a + $b;
}
var_dump(sum(1, 2));//float(3)

返回一个对象

class C{}
function get_C(): C{
    return new C;
}
var_dump(get_C());

可变函数

变量名后有圆括号,可变函数可以用来实现包括回调函数,函数表在内的一些用途,只能用于用户自定义函数

function a(){
    echo 123;
}
$a = 'a';
$a();//123

调用一个对象的方法

class A{
    function c(){
        $name = 'b';
        $this->$name();
    }
    function b(){
        echo 'I am here!';
    }
}
$a = new A();
$name = 'c';
$a->$name();//I am here!

复杂的callables

class Foo
{
    static function bar()
    {
        echo "bar\n";
    }
    function baz()
    {
        echo "baz\n";
    }
}

$func = ["Foo", "bar"];
$func();
["Foo", "bar"]();//不要问为什么,规定这样
$func = [new Foo, "baz"];
$func(); //"baz"
[new Foo, "baz"]();//不要问为什么,规定这样
//php7.0+
$func = "Foo::bar";
$func();
"Foo::bar"();//不要问为什么,规定这样

内置函数

判断函数是否存在

function_exists() — 如果给定的函数已经被定义就返回 TRUE

匿名函数 

 Anonymous function 也叫闭包函数(Closures)

允许 临时创建一个没有指定名称的函数。最经常用作回调函数(callback)参数的值 

匿名函数目前是通过Closure类实现的

$a =  function ($b){
    echo $b;
};
$a('xx');//xx
var_dump($a);//object(Closure)#1 (1) { ["parameter"]=> array(1) { ["$b"]=> string(10) "" } }

闭包函数也可以作为变量的值来使用。PHP 会自动把此种表达式转换成内置类 Closure 的对象实例。把一个 closure 对象赋值给一个变量的方式与普通变量赋值的语法是一样的,最后也要加上分号

$a = 'xx';
function ($b){
    echo $b;
}($a);//报错,没有这种写法
function call_back($b, $c, $func){
    return $func($b, $c);
};
echo call_back(3, 2, function($b, $c){
    return $b*$c;
});//6

 闭包可以从父作用域中继承变量。任何此类变量都可以用use语言结构传递进去。

超全局变量或$this和参数重名,这些穿不进去 php7.1+

 闭包的父作用域是定义该闭包的函数时的作用域

$msg1 = 'hello';
$msg2 = 'world';
$a = function()use($msg1, $msg2){//定义的时候已经传入
    echo $msg1.$msg2;
};
$a();//helloworld
$msg1 = '额';
$a();//helloworld
$b = function()use(&$msg1,&$msg2){//传引入
    echo $msg1.$msg2;
};
$b();//额world
$msg1 = 'hello';
$b();//helloworld
//array_walk(array, function, arg..),为数组的每一个成员执行function,并传入参数
function getStr($value, $key, $arg){
    echo $value.' got a id of '.$key.' in '.$arg;
}
$arr = ['a'=>'tony', 'b'=>'kevin'];
array_walk($arr, 'getStr', '2019');//tony got a id of a in 2019kevin got a id of b in 2019


// 一个基本的购物车,包括一些已经添加的商品和每种商品的数量。
// 其中有一个方法用来计算购物车中所有商品的总价格,该方法使
// 用了一个 closure 作为回调函数。
class Cart
{
    const PRICE_BUTTER  = 1.00;
    const PRICE_MILK    = 3.00;
    const PRICE_EGGS    = 6.95;

    protected   $products = array();
    
    public function add($product, $quantity)
    {
        $this->products[$product] = $quantity;
    }
    
    public function getQuantity($product)
    {
        return isset($this->products[$product]) ? $this->products[$product] :
               FALSE;
    }
    
    public function getTotal($tax)
    {
        $total = 0.00;
        
        $callback =
            function ($quantity, $product) use ($tax, &$total)
            {
                $pricePerItem = constant(__CLASS__ . "::PRICE_" .
                    strtoupper($product));//__CLASS__获取当前类名,contant()返回一个常量的值
                $total += ($pricePerItem * $quantity) * ($tax + 1.0);
            };//父作用域在getTotal函数内,$tax和&total有效
        
        array_walk($this->products, $callback);
        return round($total, 2);;
    }
}
//加入购物车
$my_cart = new Cart;
$my_cart->add('butter', 2);
$my_cart->add('milk', 4);
$my_cart->add('eggs', 6);
//打出总价格,加上5%的税
echo $my_cart->getTotal(0.05);//58.49

当类内的函数中有匿名函数,其中的$this,将会自动绑定到类上 php5.4+ 

如不需要绑定,则使用静态的匿名函数

class Foo
{
    function __construct()
    {
        $func = static function() {
            var_dump($this);//Using $this when not in object context 
            //不在对象作用域中使用$this
        };
        $func();
    }
};
new Foo();

补充信息:Closure类

/*Closure对象
 有三个函数
 1、__construct 用于禁止实例化的构造函数
 2、bind复制一个闭包,绑定到制定的$this对象和类作用域,这个是bingTo的静态版本
 3、bingTo复制当前闭包对象,绑定指定的$this对象和类作用域
 public Closure::bindTo ( object $newthis [, mixed $newscope = 'static' ] ) : Closure
 $newthis //新的this
 newscope 关联到匿名函数的类作用域,或者 'static' 保持当前状态。如果是一个对象,则使用这个对象的类型为心得类作用域。 这会决定绑定的对象的 保护、私有成员 方法的可见性
 静态闭包不能有绑定的对象( newthis 参数的值应该设为 NULL)不过仍然可以用 bindTo 方法来改变它们的类作用域
*/
class Student {
    public $name, $age;
    static $school = 'shuozhong';
    function __construct($name, $age) {
        $this->name = $name;
        $this->age = $age;
    }
    function getClosure($isStatic) {
        if($isStatic)
            return static function() { return __CLASS__; };
        return function() { return $this->val; };
    }
    
}
class Student1 {
    public $name, $age;
    static $school = 'guizhong';
    function __construct($name, $age) {
        $this->name = $name;
        $this->age = $age;
    }
    function getClosure($isStatic) {
        if($isStatic)
            return static function() { return __CLASS__; };
        return function() { return $this->val; };
    }
    
}

$func = function(){
    echo "My name is {$this->name} from ".static::$school." and I am {$this->age} </br>";
};

$sd1 = new Student('张三', 14);
$sd2 = new Student1('李四', 13);
//绑定$this和作用域
$newFunc = $func->bindTo($sd1);
$newFunc();//My name is 张三 from shuozhong and I am 14 
$newFunc = $func->bindTo($sd2);
$newFunc();//My name is 李四 from guizhong and I am 13 
//只绑定作用域
$func = function(){
    echo "My school is ".static::$school."</br>";
};
$newFunc = $func->bindTo(null, $sd1);
$newFunc();//My school is shuozhong
$newFunc = $func->bindTo(null, 'Student1');
$newFunc();//My school is guizhong
//为了与静态匿名函数比较
$newFunc = $func->bindTo($sd1);
$newFunc();//My school is shuozhong
//静态匿名函数
$func = static function(){
    echo "My school is ".static::$school."</br>";
};
//$newFunc = $func->bindTo($sd1);//Cannot bind an instance to a static closure
$newFunc = $func->bindTo(null, $sd1);
$newFunc();//My school is shuozhong
//如果你只是想要复制一个匿名函数,可以用 cloning 代替

 120、var_export()函数

$a = [1,23,4];
var_export($a);//array ( 0 => 1, 1 => 23, 2 => 4, ) 返回null
$b = var_export($a, true);//返回值
var_dump($b);//string(40) "array ( 0 => 1, 1 => 23, 2 => 4, )"

class B
{
    public $a = 123;
    public function c ()
    {
        echo 123;
    }
}

var_export(new B);//B::__set_state(array( 'a' => 123, )

122、平方**

$a = 42;
echo $a**2;//1764

 123、PHP中__FUNCTION__与__METHOD__的区别,主要在以下二点:
使用__FUNCTION__仅传回函数名称
使用__METHOD__传回类名称与函数名称

124、如何开启log_error

log_errors = on

error_log = "路径"

125、compact(string[变量的名字])创建一个包含变量名和它们的值的数组

$firstname = "Peter";
$lastname = "Griffin";
$age = "41";

$result = compact("firstname", "lastname", "age");

print_r($result);

 

posted @ 2019-05-21 09:35  ValleyUp  阅读(351)  评论(0编辑  收藏  举报