SPL 库也叫做 PHP 标准库,主要就是用于解决典型问题的一组接口或类的集合。这些典型问题包括什么呢?比如我们今天要讲的数据结构,还有一些设计模式的实现,就像我们之前讲过的观察者模式相关的接口在 SPL 库中都有提供。话说回来,在 PHP 中,由于语言的特点,其实很多数据结构都和我们用 C 语言实现的略有不同,比如说链表,由于没有结构的概念,所以我们一般会使用类来代表链表的结点。除了这个之外,要手写链表还需要链表的增、删、改、查等操作,而 SPL 库中其实已经帮我们提供了一个双向链表的实现,并且还可以在这个链表的基础上直接实现栈和队列的操作。

双向链表

在 SPL 库中,双向链表只需要实例化一个 SplDoublyLinkedList 类就可以了,然后我们就可以对这个实例化之后的双向链表对象进行各种操作。

$dll = new SplDoublyLinkedList();

var_dump($dll->isEmpty()); // bool(true)

$dll->push(200);
$dll->push(300);
$dll->unshift("五号");
$dll->add(2, "六号"); var_dump($dll->isEmpty()); // bool(false) var_dump($dll);
// object(SplDoublyLinkedList)#1 (2) {
// ["flags":"SplDoublyLinkedList":private]=>
// int(0)
// ["dllist":"SplDoublyLinkedList":private]=>
// array(4) {
// [0]=>
// string(6) "五号"
// [1]=>
// int(200)
// [2]=>
// string(6) "六号"
// [3]=>
// int(300)
// }
// }

从代码中可以看出,push() 、 unshift() 、add() 方法都是向链表中添加数据,而 isEmpty() 则用于判断链表是否为空。直接打印显示链表的内容,可以看到链表的内部是一个数组数据。

var_dump($dll->top()); // int(300)
var_dump($dll->bottom()); // string(6) "五号" var_dump($dll->pop()); // int(300)
var_dump($dll->shift()); // string(6) "五号" var_dump($dll->serialize()); // string(25) "i:0;:i:200;:s:6:"六号";"
var_dump($dll->count()); // int(2)

top() 和 bottom() 分别获取的是链表的顶部和底部的数据。而 pop() 和 shift() 则是分别从底部和顶部弹出数据。后面我们会看到,根据设置的不同,它他们也会遵循使用栈还是队列的方式来弹出数据。

serialize() 方法可以直接获得序列化后的链表内容。count() 方法就是返回链表内元素的数量了。

$dll->offsetSet(1, '修改成新六号');
var_dump($dll->offsetGet(1)); // string(18) "修改成新六号"
var_dump($dll->offsetExists(1)); // bool(true)
$dll->offsetUnset(1);
var_dump($dll->offsetExists(1)); // bool(false)

offset 相关的方法函数是根据偏移值来操作链表内的数据,其实就可以理解成是根据位置下标来操作数据。

在默认情况下,我们遍历链表的话,是类似于队列的形式进行输出的,也就是先进先出的状态。

for($i=1;$i<5;$i++){
$dll->push($i);
} var_dump($dll->getIteratorMode()); // int(0)
$dll->rewind();
while($dll->valid()){
echo '============', PHP_EOL;
echo 'key:', $dll->key(), PHP_EOL;
echo ' current:', $dll->current(), PHP_EOL;
$dll->next();
}
// ============
// key:0
// current:200
// ============
// key:1
// current:1
// ============
// key:2
// current:2
// ============
// key:3
// current:3
// ============
// key:4
// current:4

通过 rewind() 将链表指针恢复到开头,然后通过 valid() 方法判断当前数据是否有效,next() 用于将链表指针移动到下一个,就可以进行数据的遍历。我们通过设置链表的迭代模式,就可以改变链表的迭代输出规则,比如我们需要类似栈类型的后进先出。

$dll->setIteratorMode(SplDoublyLinkedList::IT_MODE_LIFO);
$dll->rewind();
while($dll->valid()){
echo 'IT_MODE_LIFO============', PHP_EOL;
echo 'key:', $dll->key(), PHP_EOL;
echo ' current:', $dll->current(), PHP_EOL;
$dll->next();
}
// IT_MODE_LIFO============
// key:4
// current:4
// IT_MODE_LIFO============
// key:3
// current:3
// IT_MODE_LIFO============
// key:2
// current:2
// IT_MODE_LIFO============
// key:1
// current:1
// IT_MODE_LIFO============
// key:0
// current:200

另外,它还有一个比较好玩的迭代模式,就是直接边遍历,边删除。

$dll->setIteratorMode(SplDoublyLinkedList::IT_MODE_DELETE);
$dll->rewind();
while($dll->valid()){
echo 'IT_MODE_DELETE============', PHP_EOL;
echo 'key:', $dll->key(), PHP_EOL;
echo ' current:', $dll->current(), PHP_EOL;
$dll->next();
}
var_dump($dll);
// object(SplDoublyLinkedList)#1 (2) {
// ["flags":"SplDoublyLinkedList":private]=>
// int(1)
// ["dllist":"SplDoublyLinkedList":private]=>
// array(0) {
// }
// }

在使用 IT_MODE_DELETE 进行遍历之后,链表里面的数据内容也就变成空的了。默认情况下,这个 IteraotrMode 的内容是 SplDoublyLinkedList::IT_MODE_KEEP | SplDoublyLinkedList::IT_MODE_FIFO 这个值,表示的就是数据保持原来的状态并且使用先进先出的规则。

栈类 SplStack 其实和后面的队列类 SplQueue 一样,都是继承自链表类的,也就是说它们其实就是相当于设置好了 IteratorMode 的链表对象。所以它们的方法函数其实都没有什么太大的区别。

// 栈
$stack = new SplStack();
for($i=1;$i<5;$i++){
$stack->push($i);
}
var_dump($stack->getIteratorMode()); // int(6)
var_dump($stack);
// object(SplStack)#2 (2) {
// ["flags":"SplDoublyLinkedList":private]=>
// int(6)
// ["dllist":"SplDoublyLinkedList":private]=>
// array(4) {
// [0]=>
// int(1)
// [1]=>
// int(2)
// [2]=>
// int(3)
// [3]=>
// int(4)
// }
// } $stack->rewind();
while($stack->valid()){
echo '============', PHP_EOL;
echo 'key:', $stack->key(), PHP_EOL;
echo ' current:', $stack->current(), PHP_EOL;
$stack->next();
}
// ============
// key:3
// current:4
// ============
// key:2
// current:3
// ============
// key:1
// current:2
// ============
// key:0
// current:1

队列

SplQueue 队列相对于链表类和栈类来说,多了两个方法。

// 队列
$queue = new SplQueue();
for($i=1;$i<5;$i++){
$queue->enqueue($i);
}
var_dump($queue->getIteratorMode()); // int(4)
var_dump($queue);
// object(SplQueue)#3 (2) {
// ["flags":"SplDoublyLinkedList":private]=>
// int(4)
// ["dllist":"SplDoublyLinkedList":private]=>
// array(4) {
// [0]=>
// int(1)
// [1]=>
// int(2)
// [2]=>
// int(3)
// [3]=>
// int(4)
// }
// } $queue->rewind();
while($queue->valid()){
echo '============', PHP_EOL;
echo 'key:', $queue->key(), PHP_EOL;
echo ' current:', $queue->current(), PHP_EOL;
echo ' info:', $queue->dequeue(), PHP_EOL;
$queue->next();
}
// ============
// key:0
// current:1
// info:1
// ============
// key:1
// current:2
// info:2
// ============
// key:2
// current:3
// info:3
// ============
// key:3
// current:4
// info:4

enqueue() 和 dequeue() 方法分别就是入队和出队的意思,其实就可以看成是 push() 和 shift() 的操作,底部添加顶部弹出。

堆栈堆栈,总会有人把堆和栈说成是一个东西,其实它们可是完全不同的两个数据结构哦。栈是线性的逻辑结构,而堆则一般是树形的逻辑结构,当然,它们的存储结构都是可以用相同的链表或顺序表来表示的。在堆中,有大顶堆和小顶堆的概念,SPL 也为我们分别提供了这两种实现。(不了解堆的同学可以自行查阅相关资料)

大顶堆

$maxHeap = new SplMaxHeap();
for($i=1;$i<5;$i++){
$maxHeap->insert($i);
} var_dump($maxHeap);
// object(SplMaxHeap)#4 (3) {
// ["flags":"SplHeap":private]=>
// int(0)
// ["isCorrupted":"SplHeap":private]=>
// bool(false)
// ["heap":"SplHeap":private]=>
// array(4) {
// [0]=>
// int(4)
// [1]=>
// int(3)
// [2]=>
// int(2)
// [3]=>
// int(1)
// }
// } var_dump($maxHeap->count()); // int(4)
var_dump($maxHeap->top()); // int(4) var_dump($maxHeap->extract()); // int(4) var_dump($maxHeap->count()); // int(3)
var_dump($maxHeap->top()); // int(3) var_dump($maxHeap);
// object(SplMaxHeap)#4 (3) {
// ["flags":"SplHeap":private]=>
// int(0)
// ["isCorrupted":"SplHeap":private]=>
// bool(false)
// ["heap":"SplHeap":private]=>
// array(3) {
// [0]=>
// int(3)
// [1]=>
// int(1)
// [2]=>
// int(2)
// }
// } $maxHeap->rewind();
while($maxHeap->valid()){
echo '============', PHP_EOL;
echo 'key:', $maxHeap->key(), PHP_EOL;
echo ' current:', $maxHeap->current(), PHP_EOL;
$maxHeap->next();
}
// ============
// key:2
// current:3
// ============
// key:1
// current:2
// ============
// key:0
// current:1 var_dump($maxHeap->isCorrupted()); // bool(false)
$maxHeap->recoverFromCorruption();

SplMaxHeap 类就是用于生成大顶堆实例的类模板。它通过 insert() 方法插入数据,通过 extract() 方法抽取数据,同样也包括 count() 和 top() 这类的常用方法函数,以及遍历相关的那些方法函数。

另外,堆的操作中还包括两个方法函数,分别用于判断堆是否处于损坏状态 isCorrupted() 以及从损坏状态恢复 recoverFromCorruption() 相关的操作函数。

小顶堆

小顶堆的内容和大顶堆就完全一样了,只是它的内部结构不同,大顶堆是父结点总是最大的,而小顶堆就是反过来父结点总是最小的数据。

$minHeap = new SplMinHeap();
for($i=1;$i<5;$i++){
$minHeap->insert($i);
}
var_dump($minHeap);
// object(SplMinHeap)#5 (3) {
// ["flags":"SplHeap":private]=>
// int(0)
// ["isCorrupted":"SplHeap":private]=>
// bool(false)
// ["heap":"SplHeap":private]=>
// array(4) {
// [0]=>
// int(1)
// [1]=>
// int(2)
// [2]=>
// int(3)
// [3]=>
// int(4)
// }
// } var_dump($minHeap->top()); // int(1)

大顶堆实现的优先队列

除了大顶堆和小顶堆的普通操作之外,SPL 库中还有一个通过大顶堆来实现的优先队列的类模板。

$pQueue = new SplPriorityQueue();
for($i=1;$i<5;$i++){
$pQueue->insert($i, random_int(1,10));
}
var_dump($pQueue);
// object(SplPriorityQueue)#6 (3) {
// ["flags":"SplPriorityQueue":private]=>
// int(1)
// ["isCorrupted":"SplPriorityQueue":private]=>
// bool(false)
// ["heap":"SplPriorityQueue":private]=>
// array(4) {
// [0]=>
// array(2) {
// ["data"]=>
// int(3)
// ["priority"]=>
// int(10)
// }
// [1]=>
// array(2) {
// ["data"]=>
// int(4)
// ["priority"]=>
// int(7)
// }
// [2]=>
// array(2) {
// ["data"]=>
// int(1)
// ["priority"]=>
// int(3)
// }
// [3]=>
// array(2) {
// ["data"]=>
// int(2)
// ["priority"]=>
// int(2)
// }
// }
// } while($pQueue->valid()){
var_dump($pQueue->extract());
}
// int(3)
// int(4)
// int(1)
// int(2)

它的操作方法函数和堆的操作方法函数都是一样的,只是 insert() 方法中多了一个参数可以设置数据的优先级。通过设置不同的优先级我们可以看到数据以及遍历输出的结果都会发生变化,顺序都是以优先级来确定的。

固定数组

什么叫固定数组呢?在 PHP 中,数组这个结构非常强大,它即可以是普通下标类型的数组,也可以 HashMap键值对 形式的数组,它的长度也是不受限制的,只要内存够就可以灵活地处理数组的长度。不过在静态语言中,特别是我们学习过的 C 语言中,数组都是固定长度的,也就是说,数组的内存大小是在数组初始化的时候就确定好的,如果超出了数组长度的操作发生,就会产生越界问题。还是通过一个例子来看吧。

// 数组
$norArr = [];
$norArr[1] = 'b';
$norArr[4] = 'f'; var_dump($norArr);
// array(2) {
// [1]=>
// string(1) "b"
// [4]=>
// string(1) "f"
// } $fArr = new SplFixedArray(5);
$fArr[1] = 'b';
$fArr[4] = 'f'; var_dump($fArr);
// object(SplFixedArray)#7 (5) {
// [0]=>
// NULL
// [1]=>
// string(1) "b"
// [2]=>
// NULL
// [3]=>
// NULL
// [4]=>
// string(1) "f"
// }

norArr 是普通的 PHP 数组,我们添加了两个数据之后在这个数组中只有两个元素。下面的 SplFixedArray 类实例化出来的 fArr 则是固定数组。它在实例化的时候必须传递一个构造参数来指定数组长度。可以看到,fArr 输出的结果是固定有 5 个数据的,并且我们没有赋值的数据都会给一个默认的 NULL 值。是不是和 C 的数组一样一样的。

当然,固定数组就会有数组下标越界的问题了。

$fArr[6] = 'h'; // Fatal error: Uncaught RuntimeException: Index invalid or out of range

不过我们可以手动地修改数组的大小来改变数据的长度。

$fArr->setSize(7);
$fArr[6] = 'h';
var_dump($fArr->getSize()); // int(7)

现在,数组的长度就是 7 了,可以存放 7 条数据。它也可以直接从一个普通数组转换过来,不过需要注意的是,转换数组必须是数字下标类型的数组,字符串键的 HashMap 数组是不可以的哦。

$fArr2 = SplFixedArray::fromArray(range(1,3));
var_dump($fArr2);
// object(SplFixedArray)#8 (3) {
// [0]=>
// int(1)
// [1]=>
// int(2)
// [2]=>
// int(3)
// } // $fArr3 = SplFixedArray::fromArray(['new'=>1, 'old'=>2]);
// var_dump($fArr3);
// PHP Fatal error: Uncaught InvalidArgumentException: array must contain only positive integer keys

剩下的就是和其它数据结构一样的一些操作方法函数了。

var_dump($fArr->count()); // int(7)

var_dump($fArr->offsetGet(2)); // NULL
$fArr->offsetSet(2, 'new');
var_dump($fArr->offsetGet(2)); // string(3) "new"
var_dump($fArr->offsetExists(2)); // bool(true)
$fArr->offsetUnset(2);
var_dump($fArr->offsetExists(2)); // bool(false) $fArr->rewind();
while($fArr->valid()){
echo '============', PHP_EOL;
echo 'key:', $fArr->key(), PHP_EOL;
echo ' current:', $fArr->current(), PHP_EOL;
$fArr->next();
}
// ============
// key:0
// current:
// ============
// key:1
// current:b
// ============
// key:2
// current:
// ============
// key:3
// current:
// ============
// key:4
// current:f
// ============
// key:5
// current:
// ============
// key:6
// current:h

既然它是一种数组对象,那么迭代其实不用这么麻烦的,我们直接通过 for 和 foreach 就可以了。它和其它的数组结构一样,都实现了 Iterator 和 Countable 这两个接口,都是可以通过 for 和 foreach 来进行遍历的。

foreach($fArr as $f){
var_dump($f);
}
for($i=0;$i<count($fArr);$i++){
var_dump($fArr[$i]);
}

对象数据映射

最后一种数据结构,对象数据映射。这是个什么鬼?最简单直接的理解其实就是把一个对象当成是 【键】,然后以这些键形成一个数组结构。

$os = new SplObjectStorage();

$o1 = new stdClass;
$o2 = new stdClass;
$o3 = new stdClass;
$o4 = new stdClass;
$o5 = new stdClass; $os->attach($o1);
$os->attach($o2);
$os->attach($o3);
$os->attach($o4, 'd4');
$os->attach($o5, 'd5'); var_dump($os);
// object(SplObjectStorage)#9 (1) {
// ["storage":"SplObjectStorage":private]=>
// array(5) {
// ["00000000736a0aba000000002f97228d"]=>
// array(2) {
// ["obj"]=>
// object(stdClass)#10 (0) {
// }
// ["inf"]=>
// NULL
// }
// ["00000000736a0abb000000002f97228d"]=>
// array(2) {
// ["obj"]=>
// object(stdClass)#11 (0) {
// }
// ["inf"]=>
// NULL
// }
// ["00000000736a0abc000000002f97228d"]=>
// array(2) {
// ["obj"]=>
// object(stdClass)#12 (0) {
// }
// ["inf"]=>
// NULL
// }
// ["00000000736a0abd000000002f97228d"]=>
// array(2) {
// ["obj"]=>
// object(stdClass)#13 (0) {
// }
// ["inf"]=>
// string(2) "d4"
// }
// ["00000000736a0abe000000002f97228d"]=>
// array(2) {
// ["obj"]=>
// object(stdClass)#14 (0) {
// }
// ["inf"]=>
// string(2) "d5"
// }
// }
// }

是不是有点意思,attach() 就可以向这个 SplObjectStorage 对象存储映射类中添加数据。它的第二个参数可以指定一个数据内容,其实就可以看作是普通数组中的 值 。

var_dump($os->count()); // int(5)
$os->detach($o2);
var_dump($os->count()); // int(4) var_dump($os->contains($o2)); // bool(false)
var_dump($os->contains($o3)); // bool(true) var_dump($os->getHash($o4)); // string(32) "000000003e67a2330000000040e598c9" var_dump($os->offsetGet($o4)); // string(2) "d4"
$os->offsetSet($o4, 'new d4');
var_dump($os->offsetGet($o4)); // string(6) "new d4"
var_dump($os->offsetExists($o4)); // bool(true)
$os->offsetUnset($o4);
var_dump($os->offsetExists($o4)); // bool(false) $os->rewind();
$os[$o1] = 'new d1';
while($os->valid()){
echo '============', PHP_EOL;
echo 'key:', $os->key(), PHP_EOL;
if($os->getInfo() === NULL){
$os->setInfo('new iter info');
}
echo ' info:', $os->getInfo(), PHP_EOL;
echo ' current:', PHP_EOL;
var_dump($os->current()); $os->next();
}
// ============
// key:0
// info:new d1
// current:
// object(stdClass)#10 (0) {
// }
// ============
// key:1
// info:new iter info
// current:
// object(stdClass)#12 (0) {
// }
// ============
// key:2
// info:d5
// current:
// object(stdClass)#14 (0) {
// }

其它的遍历查询操作都是和其它数据结构的操作类似的,这里就不多说了。其中比较特别的是 detach() 方法是删除数据的,getHash() 则是获取这个对象在存储集合中的 Hash 值的,这个值也可以看做是这个对象在这个对象映射集合中的下标,我们其它的针对对象的操作判断其实是都是在内部转换成这个数组下标来进行操作的。

总结

其实这一圈学习下来,突然发现有了 SPL 的这几个数据结构之后,我们在 PHP 下面还真不太需要关心什么数据结构方面的实现了,直接通用点就上个双向链表就完了,简单的就只是写算法了。好吧,学习还是要扎实点,数据结构和算法真正要学习的其实是它内部的思想和逻辑。当然,既然已经提供了,那么我们平常的业务开发中还是更建议直接使用 SPL 的这些数据结构来处理!

测试代码:

https://github.com/zhangyue0503/dev-blog/blob/master/php/2021/01/source/3.PHP的SPL扩展库(一)数据结构.php

参考文档:

https://www.php.net/manual/zh/spl.datastructures.php

PHP的SPL扩展库(一)数据结构的更多相关文章

  1. PHP SPL标准库之数据结构栈(SplStack)介绍(基础array已经可以解决很多问题了,现在开始解决问题)

    PHP SPL标准库之数据结构栈(SplStack)介绍(基础array已经可以解决很多问题了,现在开始解决问题) 一.总结 SplStack就是继承双链表(SplDoublyLinkedList)实 ...

  2. PHP SPL扩展库简单使用

    1. __autoload 这是一个自动加载函数,在PHP5中,当我们实例化一个未定义的类时,就会触发此函数.看下面例子: ./myClass.php <?php class myClass { ...

  3. 【SPL标准库专题(1)】 SPL简介

    什么是SPL SPL是Standard PHP Library(PHP标准库)的缩写. 根据官方定义,它是"a collection of interfaces and classes th ...

  4. php spl标准库简介(SPL是Standard PHP Library(PHP标准库)(直接看代码实例,特别方便)

    php spl标准库简介(SPL是Standard PHP Library(PHP标准库)(直接看代码实例,特别方便) 一.总结 直接看代码实例,特别方便易懂 thinkphp控制器利眠宁不支持(说明 ...

  5. PHP的SPL标准库里面的堆(SplHeap)怎么使用

    PHP的SPL标准库里面的堆(SplHeap)怎么使用 一.总结 1.因为SplHeap是抽象类,所以要先继承,实现里面的抽象方法compare后,才能new对象使用. 二.PHP的SPL标准库里面的 ...

  6. Z.ExtensionMethods 一个强大的开源扩展库

    今天有意的在博客园里面搜索了一下 Z.ExtensionMethods 这个扩展类库,确发现只搜到跟这个真正相关的才两篇博文而已,我都点进去看了一下,也都只是提到而已,没有专门介绍,才引起我写这篇文档 ...

  7. PHP使用mysqli扩展库实现增删改查(面向对象版)

    mysqli扩展库是mysql扩展库的改进版本,在mysql扩展库的基础上提高了稳定性和效率,mysqli扩展库有两套东西,一套就是面向过程的mysqli另一套是面向对象的mysqli.操作方式大体和 ...

  8. PHP mysqli 扩展库(面向对象/数据库操作封装/事务控制/预编译)

    1.和mysql扩展库的区别: (1   安全性.稳定性更高 (2  提供了面向对象和面向过程两种风格 2.php.ini  中的  extension=php_mysqli.dll 解除封印 3.面 ...

  9. PHP基础Mysql扩展库

    mysql扩展库操作步骤如下: 1.连接数据库 2.选择数据库 3.设置操作编码 4.发送指令sql,并返回结果集     ddl:数据定义语句     dml:数据操作语句     dql:数据查询 ...

随机推荐

  1. 【开发工具】idea常用配置

    1. 设置鼠标滚轮修改字体大小 我们可以勾选此设置后,增加Ctrl + 鼠标滚轮 快捷键来控制代码字体大小显示. 2. 设置鼠标悬浮提示  3. 设置自动导包功能 Add unambiguous im ...

  2. C++CLR类库封装Native类库并用C#调用 - 草稿

    1.创建Native类库 新建项目->其他语言->Visual C++->Win32控制台应用程序->DLL     添加头文件       添加源文件       选择生成路 ...

  3. ArcGIS Engine中实现ArcMap的捕捉效果

    注意要将捕捉相关接口的对象放在OnCreate方法中,这样在初始化就可以有捕捉效果,(捕捉对象赋值放在OnClick中出现第一次点击之前不能捕捉的BUG) 这里是直接在工具中实现的 ,可以按需求将捕捉 ...

  4. linux使用xampp安装MediaWiki环境

    1.下载并安装xampp 下载xampp 在下载页面下载. 放置到相应目录 将xampp-linux-x64-5.6.3-0-installer.run文件复制到部署机器的/root目录下 安装 [r ...

  5. Faiss使用多线程出现的性能问题

    Faiss使用多线程出现的性能问题 faiss在增加CPU的情况下,反而出现效率低下的问题. 从理论上看,作为一个CPU/GPU计算型的应用,更多的核意味着更大的计算吞吐能力,性能只会越来越好才是. ...

  6. ES6——静态属性与静态方法

    静态方法只能写在class内,constructor外.通过static关键字声明 静态属性只能写在class外,通过 类名.属性名 = 属性值 声明 //静态属性与静态方法(ES6明确规定,Clas ...

  7. 证明:(a,[b,c]) = [(a,b),(a,c)]

    这题是潘承洞.潘承彪所著<初等数论>(第三版)第一章第5节里一个例题,书中采用算术基本定理证明,并指出要直接用第4节的方法来证是较困难的. 现采用第4节的方法(即最大公约数理论里的几个常用 ...

  8. 紫色飞猪的研发之旅--06go自定义状态码

    在实际开发中,需要前后端需要协商状态码,状态码用于后端返前端时使用.在一个团队中,定义的状态码讲道理应该是一致的,项目开始的起始阶段状态码应该是定义了个七七八八的,随着功能的叠加而不断增加.此系列将围 ...

  9. JS 根据id实现局部打印

    // 打印初审收费清单     getOrderCostBille(){       var head_str = "<html><head><title> ...

  10. client-go实战之一:准备工作

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...