一, HTTP中PATCH和PUT方法的区别?
PATCH方法是新引入的,是对PUT方法的补充,用来对已知资源进行局部更新
patch
方法用来更新局部资源,这句话我们该如何理解?
假设我们有一个UserInfo
,里面有userId
, userName
, userGender
等10个字段。可你的编辑功能因为需求,在某个特别的页面里只能修改userName
,这时候的更新怎么做?
人们通常(为徒省事)把一个包含了修改后userName
的完整userInfo
对象传给后端,做完整更新。但仔细想想,这种做法感觉有点二,而且真心浪费带宽(纯技术上讲,你不关心带宽那是你土豪)。
于是patch
诞生,只传一个userName
到指定资源去,表示该请求是一个局部更新,后端仅更新接收到的字段。
而put
虽然也是更新资源,但要求前端提供的一定是一个完整的资源对象,理论上说,如果你用了put
,但却没有提供完整的UserInfo
,那么缺了的那些字段应该被清空
补充:
最后再补充一句,restful
只是标准,标准的意思是如果在大家都依此行事的话,沟通成本会很低,开发效率就高。但并非强制(也没人强制得了),所以你说在你的程序里把方法名从put
改成patch
没有任何影响,那是自然,因为你的后端程序并没有按照标准对两个方法做不同处理,她的表现自然是一样的
补充一下,PATCH 与 PUT 属性上的一个重要区别还在于:PUT 是幂等的,而 PATCH 不是幂等的。
幂等是一个数学和计算机学概念,在计算机范畴内表示一个操作执行任意次对系统的影响跟一次是相同。
在HTTP/1.1规范中幂等性的定义是:
Methods can also have the property of "idempotence" in that (aside from error or expiration issues) the side-effects of N > 0 identical requests is the same as for a single request.
如:POST 方法不是幂等的,若反复执行多次对应的每一次都会创建一个新资源。如果请求超时,则需要回答这一问题:资源是否已经在服务端创建了?能否再重试一次或检查资源列表?而对于幂等方法不存在这一个问题,我们可以放心地多次请求。
二,补充下基础知识 php 的变量作用域问题
一、变量范围
变量的范围即它定义的上下文背景(译者:说白了,也就是它的生效范围)。大部分的 PHP 变量只有一个单独的范围。这个单独的范围跨度同样包含了 include 和 require 引入的文件。范例:
1
2
3
4
|
<?php
$a
= 1;
include
"b.inc"
;
?>
|
这里变量 $a 将会在包含文件 b.inc 中生效。但是,在用户自定义函数中,一个局部函数范围将被引入。任何用于函数内部的变量按缺省情况将被限制在局部函数范围内。范例:
1
2
3
4
5
6
7
8
9
|
<?php
$a
= 1;
/* global scope */
function
Test() {
echo
$a
;
/* reference to local scope variable */
}
Test();
?>
|
这个脚本不会有任何输出,因为 echo 语句引用了一个局部版本的变量 $a,而且在这个范围内,它并没有被赋值。你可能注意到 PHP 的全局变量和 C 语言有一点点不同,在 C 语言中,全局变量在函数中自动生效,除非被局部变量覆盖。这可能引起一些问题,有些人可能漫不经心的改变一个全局变量。PHP 中全局变量在函数中使用时必须申明为全局。
二、The global keyword
首先,一个使用 global 的例子:
例子 12-1. 使用 global
1
2
3
4
5
6
7
8
9
10
11
12
|
<?php
$a
= 1;
$b
= 2;
function
Sum() {
global
$a
,
$b
;
$b
=
$a
+
$b
;
}
Sum();
echo
$b
;
?>
|
以上脚本的输出将是 "3"。在函数中申明了全局变量 $a 和 $b,任何变量的所有引用变量都会指向到全局变量。对于一个函数能够申明的全局变量的最大个数,PHP 没有限制。
在全局范围内访问变量的第二个办法,是用特殊的 PHP 自定义 $GLOBALS 数组。前面的例子可以写成:
例子 12-2. 使用 $GLOBALS 替代 global
1
2
3
4
5
6
7
8
9
10
11
|
<?php
$a
= 1;
$b
= 2;
function
Sum() {
$GLOBALS
[
"b"
] =
$GLOBALS
[
"a"
] +
$GLOBALS
[
"b"
];
}
Sum();
echo
$b
;
?>
|
在 $GLOBALS 数组中,每一个变量为一个元素,键名对应变量名,值变量的内容。$GLOBALS 之所以在全局范围内存在,是因为 $GLOBALS 是一个超全局变量。以下范例显示了超全局变量的用处:
例子 12-3. 演示超全局变量和作用域的例子
1
2
3
4
5
6
7
8
9
10
11
12
|
<?php
function
test_global() {
// 大多数的预定义变量并不 "super",它们需要用 'global' 关键字来使它们在函数的本地区域中有效。
global
$HTTP_POST_VARS
;
print
$HTTP_POST_VARS
[
'name'
];
// Super globals 在任何范围内都有效,它们并不需要 'global' 声明。Super globals 是在 PHP 4.1.0 引入的。
print
$_POST
[
'name'
];
}
?>
|
三、使用静态变量
变量范围的另一个重要特性是静态变量(static variable)。静态变量仅在局部函数域中存在,但当程序执行离开此作用域时,其值并不丢失。看看下面的例子:
例子 12-4. 演示需要静态变量的例子
1
2
3
4
5
6
7
|
<?php
function
Test() {
$a
= 0;
echo
$a
;
$a
++;
}
?>
|
本函数没什么用处,因为每次调用时都会将 $a 的值设为 0 并输出 "0"。将变量加一的 $a++ 没有作用,因为一旦退出本函数则变量 $a 就不存在了。要写一个不会丢失本次计数值的计数函数,要将变量 $a 定义为静态的:
例子 12-5. 使用静态变量的例子
1
2
3
4
5
6
7
|
<?php
function
Test() {
static
$a
= 0;
echo
$a
;
$a
++;
}
?>
|
现在,每次调用 Test() 函数都会输出 $a 的值并加一。
静态变量也提供了一种处理递归函数的方法。递归函数是一种调用自己的函数。写递归函数时要小心,因为可能会无穷递归下去。必须确保有充分的方法来中止递归。以下这个简单的函数递归计数到 10,使用静态变量 $count 来判断何时停止:
例子 12-6. 静态变量与递归函数
1
2
3
4
5
6
7
8
9
10
11
|
<?php
function
Test() {
static
$count
= 0;
$count
++;
echo
$count
;
if
(
$count
< 10) {
Test ();
}
}
?>
|
注意: 静态变量可以按照上面的例子声明。如果在声明中用“表达式的结果”对其赋值会导致解析错误。
例子 12-7. 声明静态变量
1
2
3
4
5
6
7
8
9
10
|
<?php
function
foo() {
static
$int
= 0;
// correct
static
$int
= 1+2;
// wrong (as it is an expression)
static
$int
= sqrt(121);
// wrong (as it is an expression too)
$int
++;
echo
$int
;
}
?>
|
四、全局和静态变量的引用
在 Zend 引擎 1 代,驱动了 PHP4,对于变量的 static 和 global 定义是以 references 的方式实现的。例如,在一个函数域内部用 global 语句导入的一个真正的全局变量实际上是建立了一个到全局变量的引用。这有可能导致预料之外的行为,如以下例子所演示的:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
<?php
function
test_global_ref() {
global
$obj
;
$obj
= &
new
stdclass;
}
function
test_global_noref() {
global
$obj
;
$obj
=
new
stdclass;
}
test_global_ref();
var_dump(
$obj
);
test_global_noref();
var_dump(
$obj
);
?>
|
执行以上例子会导致如下输出:
1
2
3
4
|
NULL
object(stdClass)(0) {
}
|
类似的行为也适用于 static 语句。引用并不是静态地存储的:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
<?php
function
&get_instance_ref() {
static
$obj
;
echo
"Static object: "
;
var_dump(
$obj
);
if
(!isset(
$obj
)) {
// 将一个引用赋值给静态变量
$obj
= &
new
stdclass;
}
$obj
->property++;
return
$obj
;
}
function
&get_instance_noref() {
static
$obj
;
echo
"Static object: "
;
var_dump(
$obj
);
if
(!isset(
$obj
)) {
// 将一个对象赋值给静态变量
$obj
=
new
stdclass;
}
$obj
->property++;
return
$obj
;
}
$obj1
= get_instance_ref();
$still_obj1
= get_instance_ref();
echo
"<br/>"
;
$obj2
= get_instance_noref();
$still_obj2
= get_instance_noref();
?>
|
执行以上例子会导致如下输出:
1
2
3
4
5
6
7
8
|
Static object: NULL
Static object: NULL
Static object: NULL
Static object: object(stdClass)(1) {
[
"property"
]=>
int(1)
}
|
上例演示了当把一个引用赋值给一个静态变量时,第二次调用 &get_instance_ref() 函数时其值并没有被记住。