json_encode
原来只知道json_encode()
可以把数组格式化为json格式,原来json_encode()
还可以把字符串格式化为json格式,
不过对该格式化后的json对象,使用json_decode($json)
后还是字符串,而不是数组。
如:
<?php
$string = '{"name":"John", "age":30, "city":"New York"}';
$jsonArray = json_encode($string);
echo $jsonArray; // 输出: "{\"name\":\"John\", \"age\":30, \"city\":\"New York\"}"
echo json_decode($jsonArray, true); // 输出:{"name":"John", "age":30, "city":"New York"}
常规数组操作:
<?php
$arr = ['name' => 'John', 'age' => 30, 'city' => 'New York'];
$str = json_encode($arr);
echo $str; // {"name":"John","age":30,"city":"New York"}
$str2 = '{"name":"John","age":30,"city":"New York"}';
$arr2 = json_decode($str2, true);
print_r($arr2);
// 输出
Array
(
[name] => John
[age] => 30
[city] => New York
)
字符串拼接:
<?php
$str = '{' .'"name":"' .'John' .'","age":' .'30' .',"city":"' .'New York' .'"' .'}';
$arr = json_decode($str, true);
print_r($arr);
// 输出
Array
(
[name] => John
[age] => 30
[city] => New York
)
参考地址 https://www.php.net/manual/zh/function.json-encode.php
函数原型: json_encode(mixed $value, int $flags = 0, int $depth = 512): string|false
$flags 参数有2个比较常用到的参数值:
- JSON_UNESCAPED_UNICODE(中文不转为unicode ,对应的数字 256)
- JSON_UNESCAPED_SLASHES (不转义反斜杠,对应的数字 64)
通常json_encode只能传入一个常量,如果同时使用2个常量怎么办?
JSON_UNESCAPED_UNICODE + JSON_UNESCAPED_SLASHES = 320
使用方法:json_encode($arr, 320)
,即可完成同时使用2个常量,会保留 / 和 UNICODE字符(如:中文)。
如下:
<?php
$arr = ['/ a 你好'];
echo json_encode($arr); // ["\/ a \u4f60\u597d"]
echo json_encode($arr, 320); // ["/ a 你好"]
array_map
array_map()
可以循环对数组内每个元素进行操作。
array_map()函数:多数组回调函数,将回调函数作用到给定数组的单元上
- 语法:
array array_map ( callback callback, array arr1 [, array ...] )
- 描述:返回一个数组,该数组包含了 arr1 中的所有单元经过 callback 作用过之后的单元。 callback 接受的参数数目应该和传递给 array_map() 函数的数组数目一致。
- 注意事项1:多数组回调函数作用于一个数组时,将保留原有数组的键名,也就是返回的数组的键名就是作用到给定数组的键名
- 注意事项2:多数组回调函数作用于两个或多个数组时,他们的长度要一致,并且将忽略原来多个数组的键名,统一分配数字索引作为键名
<?php
//单个数组使用的例子
$websites = array("g" => "google", "b" => "baidu", "y" => "yahoo");
//输出原数组
echo "<pre>";
print_r($websites);
echo "</pre>";
//定义对单个数组处理的回调函数
function change_value($value)
{
return ucfirst($value) . ".com";
}
$urls = array_map('change_value', $websites);
echo "<pre>";
print_r($urls);
echo "</pre>";
//多个数组使用的例子
$arr1 = array(1, 3, 5, 7);
$arr2 = array(2, 4, 6, 8);
//定义对多个数组处理的回调函数
function func1($a, $b)
{
return $a * $b;
}
$results = array_map('func1', $arr1, $arr2);
echo "利用回调函数对多个数组处理后,返回的结果:<br>";
echo "<pre>";
print_r($results);
echo "</pre>";
输出:
Array
(
[g] => google
[b] => baidu
[y] => yahoo
)
Array
(
[g] => Google.com
[b] => Baidu.com
[y] => Yahoo.com
)
利用回调函数对多个数组处理后,返回的结果:
Array
(
[0] => 2
[1] => 12
[2] => 30
[3] => 56
)
对返回的元素可以进行合并,如$string = implode(",", array_map($function, $array))
array_map原型:
/**
* Applies the callback to the elements of the given arrays
* @link http://php.net/manual/en/function.array-map.php
* @param callback $callback <p>
* Callback function to run for each element in each array.
* </p>
* @param array $arr1 <p>
* An array to run through the callback function.
* </p>
* @param array $_ [optional]
* @return array an array containing all the elements of arr1
* after applying the callback function to each one.
* @since 4.0.6
* @since 5.0
*/
function array_map($callback, array $arr1, array $_ = null) { }
call_user_func
call_user_func — 把第一个参数作为回调函数调用,原型:
call_user_func(callable $callback, mixed ...$args): mixed
第一个参数 callback 是被调用的回调函数,其余参数是回调函数的参数。
callback 可以是一个闭包函数、或者单个函数的函数名,也可以是一个类的静态函数、或者public函数。
看个例子:
<?php
class myclass {
public static function say_hello($data = '')
{
echo "Hello: $data!\n";
}
public function say_world($data = '')
{
echo "World: $data!\n";
}
}
$classname = "myclass";
call_user_func(array($classname, 'say_hello'), 'tom');
call_user_func($classname .'::say_hello', 'cand');
call_user_func(array($classname, 'say_world'), 'sala');
call_user_func($classname .'::say_world', 'yeal');
$myobject = new myclass();
call_user_func(array($myobject, 'say_hello'), 'zhangsan');
call_user_func(array($classname, 'say_world'), 'lisi');
$classname = "myclass";
$actionname = "say_world";
call_user_func(array($classname, $actionname), 'adany');
call_user_func($classname .'::' .$actionname, 'jake');
// 输出
// Hello: tom!
// Hello: cand!
// World: sala!
// World: yeal!
// Hello: zhangsan!
// World: lisi!
// World: adany!
// World: jake!
因为这个函数特殊的用法,灵活使用,可以在项目中起到依赖注入的作用。
与这个函数相关内容有:
- call_user_func_array() - 调用回调函数,并把一个数组参数作为回调函数的参数
- is_callable() - 验证值是否可以在当前范围内作为函数调用。
- Variable functions 可变函数。这意味着如果一个变量名后有圆括号,PHP 将寻找与变量的值同名的函数,并且尝试执行它。可
- ReflectionFunction::invoke() - Invokes function
- ReflectionMethod::invoke() - Invoke
函数参数…
在函数function sum(...$numbers) { }
中参数...$numbers
是什么,怎么用?
在 PHP 中,函数参数中的 ...
是用来表示函数可以接受可变数量的参数的。这被称为“参数展开”或“可变参数列表”。
当你看到 function sum(...$numbers) { }
这样的代码时,...$numbers
表示将数组 $numbers
中的所有元素作为单独的参数传递给函数 sum
。
这里,...$numbers
必须是一个数组或实现了 __invoke
方法的对象。
举个例子,假设你有一个函数 sum,它可以接受任意数量的参数,并返回它们的和:
<?php
function sum(...$numbers) {
$total = 0;
foreach ($numbers as $number) {
$total += $number;
}
return $total;
}
// 使用一个数组作为参数
$numbersArray = [1, 2, 3, 4];
echo sum(...$numbersArray); // 输出 10
// 直接传递参数
echo sum(1, 2, 3, 4); // 输出 10
在上面的例子中,...$numbers
表示函数 sum
可以接受任意数量的参数,并将它们存储在数组 $numbers
中。然后,我们遍历这个数组来计算总和。
如果你有一个数组 $numbersArray
,你可以使用 ...$numbersArray
来将数组中的每个元素作为单独的参数传递给 sum
函数。
另外,你也可以将对象作为可变参数传递,只要这个对象实现了 __invoke
方法。当对象被当作函数来调用时,__invoke
方法会被执行。
总的来说,...
在函数参数中的用法允许你以灵活的方式传递参数,包括数组中的元素或对象的方法调用。
usort
参考 https://www.php.net/manual/zh/function.usort
usort() ,使用用户自定义的比较函数对数组中的值进行排序。
函数原型:
usort(array &$array, callable $callback): true
根据用户提供的比较函数,对 array 原地排序。 $callback
是一个回调函数,返回 0 数组中比较的两个元素保持现状,
返回 1 第一个参数应该被排在第二个参数之后,返回 -1 第一个参数应该被排在第二个参数之前。
如下示例中,从小到大排序。
示例1,一维数组:
<?php
function cmp($a, $b) {
if ($a == $b) {
return 0;
}
return ($a < $b) ? -1 : 1;
}
$a = array(3, 2, 5, 6, 1);
usort($a, "cmp");
foreach ($a as $key => $value) {
echo "$key: $value\n";
}
// 输出
// 0: 1
// 1: 2
// 2: 3
// 3: 5
// 4: 6
示例2:
<?php
function cmp($a, $b)
{
if ($a == $b) {
return 0;
}
return ($a < $b) ? -1 : 1;
}
$arr = array(3, 2, 5, 6, 1);
usort($arr, function ($a, $b) {
if ($a == $b) {
return 0;
}
return ($a < $b) ? -1 : 1;
});
示例3,多维数组:
<?php
function cmp($a, $b)
{
return strcmp($a["fruit"], $b["fruit"]);
}
$fruits[0]["fruit"] = "lemons";
$fruits[1]["fruit"] = "apples";
$fruits[2]["fruit"] = "grapes";
usort($fruits, "cmp");
foreach ($fruits as $key => $value) {
echo "\$fruits[$key]: " . $value["fruit"] . "\n";
}
示例4, 使用一个对象的成员函数排序:
<?php
class TestObj
{
private string $name;
function __construct($name)
{
$this->name = $name;
}
/* This is the static comparing function: */
static function cmp_obj($a, $b)
{
return strtolower($a->name) <=> strtolower($b->name);
}
}
$a[] = new TestObj("c");
$a[] = new TestObj("b");
$a[] = new TestObj("d");
usort($a, [TestObj::class, "cmp_obj"]);
foreach ($a as $item) {
echo $item->name . "\n";
}
<=>
是一个太空船运算符(Spaceship Operator),也称为组合比较运算符,是一个三向比较运算符,它可以执行两个操作数之间的大于,小于和相等的比较。
例如:$c = $a <=> $b;
,这相当于 $c = ($a < $b) ? -1 : (($a > $b) ? 1 : 0);
。
示例5,使用闭包对多维数组进行排序:
<?php
$array[0] = array('key_a' => 'z', 'key_b' => 'c');
$array[1] = array('key_a' => 'x', 'key_b' => 'b');
$array[2] = array('key_a' => 'y', 'key_b' => 'a');
function build_sorter($key) {
return function ($a, $b) use ($key) {
return strnatcmp($a[$key], $b[$key]);
};
}
usort($array, build_sorter('key_b'));
foreach ($array as $item) {
echo $item['key_a'] . ', ' . $item['key_b'] . "\n";
}
示例5, 使用太空船运算符排序:
<?php
$people[0] = ['first' => 'Adam', 'last' => 'West'];
$people[1] = ['first' => 'Alec', 'last' => 'Baldwin'];
$people[2] = ['first' => 'Adam', 'last' => 'Baldwin'];
function sorter(array $a, array $b) {
return [$a['last'], $a['first']] <=> [$b['last'], $b['first']];
}
usort($people, 'sorter');
foreach ($people as $person) {
print $person['last'] . ', ' . $person['first'] . PHP_EOL;
}
[$a['last'], $a['first']] <=> [$b['last'], $b['first']];
的逻辑:
1. 首先比较 $a['last'] 和 $b['last']。
* 如果 $a['last'] 小于 $b['last'],返回 -1。
* 如果 $a['last'] 等于 $b['last'],继续比较 $a['first'] 和 $b['first']。
* 如果 $a['last'] 大于 $b['last'],返回 1。
2. 如果 $a['last'] 和 $b['last'] 相等,则比较 $a['first'] 和 $b['first']。
* 如果 $a['first'] 小于 $b['first'],返回 -1。
* 如果 $a['first'] 等于 $b['first'],返回 0。
* 如果 $a['first'] 大于 $b['first'],返回 1。
这个比较逻辑在处理像名字这样的数据时特别有用,因为它首先比较姓氏(last),如果姓氏相同,则进一步比较名字(first)。 这种比较方式通常用于按照人类姓名的自然排序方式进行排序。
其他常见排序函数,如:
- uasort() - 使用用户自定义的比较函数对数组进行排序并保持索引关联
- uksort() - 使用用户自定义的比较函数对数组中的键名进行排序
具体参考 https://www.php.net/manual/zh/array.sorting.php
debug_backtrace
开发中有没有碰到过这样一种情况,当一个方法被调用时,想追溯具体的调用栈。
这里就可以使用 debug_backtrace()
函数。debug_backtrace() 函数在 PHP 中返回一个包含调用堆栈信息的数组。
每个数组元素代表堆栈中的一个调用层级,是一个关联数组,包含以下可能的键(键的存在取决于调用堆栈的上下文):
file:包含当前脚本的完整路径和文件名。
line:包含当前脚本中的行号。
function:包含被调用的函数名,如果是类的方法则格式为 ClassName::methodName。
class:包含被调用函数的类名(如果存在的话)。
type:如果是对象的方法调用,这里可能是 "->"(对象实例)或 "::"(静态方法)。
args:包含传递给函数的参数列表。每个参数都是一个元素,如果是对象或数组,则是一个对象或数组的表示。
object:如果是对象的方法调用,这里会包含对象的实例。
请注意,debug_backtrace() 返回的数组中的元素是按照调用堆栈的顺序排列的, 索引 0 通常表示 debug_backtrace() 函数本身的调用, 索引 1 表示调用 debug_backtrace() 的函数或方法,依此类推。 在实际使用中,可能会有所不同,与PHP版本也有一定的关系,具体可以调试看一下。
以下是一个简化的示例,展示了 debug_backtrace() 可能返回的数据结构:
array(
0 => array(
'file' => '/path/to/script.php',
'line' => 12,
'function' => 'debug_backtrace',
'args' => array(),
),
1 => array(
'file' => '/path/to/script.php',
'line' => 20, // 这是调用 debug_backtrace 的代码行
'function' => 'B',
'class' => 'MyClass',
'type' => '->',
'args' => array(), // B 方法的参数列表
'object' => object(MyClass) // 调用 B 方法的对象实例
),
2 => array(
'file' => '/path/to/script.php',
'line' => 30, // 这是调用 B 方法的代码行(例如 A 方法)
'function' => 'A',
'class' => 'MyClass',
'type' => '->',
'args' => array(), // A 方法的参数列表
'object' => object(MyClass) // 调用 A 方法的对象实例
),
// ... 可能还有更多层级的调用信息
);
- 看一个类中方法调用的例子
<?php
class MyClass {
public function A() {
$this->B();
}
public function B() {
$trace = debug_backtrace();
var_dump($trace);
}
}
$obj = new MyClass();
$obj->A();
输出:
array(2) {
[0]=>
array(7) {
["file"]=>
string(15) "/box/script.php"
["line"]=>
int(4)
["function"]=>
string(1) "B"
["class"]=>
string(7) "MyClass"
["object"]=>
object(MyClass)#1 (0) {
}
["type"]=>
string(2) "->"
["args"]=>
array(0) {
}
}
[1]=>
array(7) {
["file"]=>
string(15) "/box/script.php"
["line"]=>
int(18)
["function"]=>
string(1) "A"
["class"]=>
string(7) "MyClass"
["object"]=>
object(MyClass)#1 (0) {
}
["type"]=>
string(2) "->"
["args"]=>
array(0) {
}
}
}
可以看到 $trace[1]
表示调用 B 的上一层方法,即 A 。
如果存在类的继承关系,子类调用父类方法,则该方法还是在子类中,注意调试区别。
- 再看一个函数调用的例子
<?php
// filename: /tmp/a.php
function a_test($str)
{
var_dump(debug_backtrace());
}
a_test('friend');
?>
<?php
// filename: /tmp/b.php
include_once '/tmp/a.php';
执行 /tmp/b.php
,输出:
array(2) {
[0]=>
array(4) {
["file"] => string(10) "/tmp/a.php"
["line"] => int(10)
["function"] => string(6) "a_test"
["args"]=>
array(1) {
[0] => &string(6) "friend"
}
}
[1]=>
array(4) {
["file"] => string(10) "/tmp/b.php"
["line"] => int(2)
["args"] =>
array(1) {
[0] => string(10) "/tmp/a.php"
}
["function"] => string(12) "include_once"
}
}
具体参考 https://www.php.net/manual/zh/function.debug-backtrace.php