redis-zset(有序集合)数据类型小结

Published on:
Tags: redis

有序集合与集合类似,不同的是,每个元素会关联一个double类型的分数

  • 增加元素
    • 增加一个或多个元素 zadd key score1 menber1 [score2 member2 score3 member3]
  • 查询元素
    • 返回集合元素数量 zcard key
    • 返回指定分数范围内元素数量 count key start stop
    • 返回指定索引范围内元素 zrange key start stop [withscores]
    • 返回指定分数范围内元素 zrangebyscore key start stop [withscores]
    • 返回指定元素的索引 zrank key member
    • 返回指定元素的分数 zscore key member
  • 修改元素
    • 修改元素分数 zincrby key increment member
  • 删除元素
    • 删除指定元素 zrem key member
    • 删除指定分数范围里的元素 zremrangebyscore key start stop
    • 删除指定索引范围里的元素 zremrangebyrank key start stop
  • 集合运算
    • 差集
      • 返回差集 sdiff num z1 z2
      • 返回差集并存储 sdiffstore destination num z1 z2
    • 交集
      • 返回交集,分数相加 zinter num key key [key …]
      • 返回交集,分数相加,另存为 zinterstore destination num key key [key …]
    • 并集
      • 返回并集 zunion num k1 k2
      • 返回并集并存储 zunionstore destination num k1 k2

zset

redis-set数据类型小结

Published on:
Tags: redis

集合具有无序性和唯一性

  • 增加元素
    • 增加一个或多个元素 sadd key menber1 [member2 member3]
  • 查询元素
    • 查询集合数量 scard key
    • 返回所有集合元素 smembers key
    • 随机返回集合元素 srandmember key [count]
  • 删除元素
    • 随机删除集合元素 spop key [count]
    • 删除集合中指定元素 srem key member [m1 m2]
  • 判断是否存在元素 sismember key member
  • 移动元素 smove source destination member
  • 集合运算
    • 差集
      • 返回差集 sdiff s1 s2
      • 返回差集并存储 sdiffstore destination s1 s2
    • 交集
      • 返回交集 sinter s1 s2
      • 返回交集并存储 sinterstore destination s1 s2
    • 并集
      • 返回并集 sunion s1 s2
      • 返回并集并存储 sunionstore destination s1 s2

set

redis-list数据类型小结

Published on:
Tags: redis

链表可以看作是一个队列,左边是队列头,右边是队列尾,增加是push,删除是pop。

  • 新增值

    • 队列头增加值 lpush key value [value2 value3]
    • 队列尾增加值 rpush key value [value2 value3]
    • 相对位置插入值 linsert key before|after pivot value
    • 新增带判断,链表不存在时增加失败
      • 队列头增加值 lpushx key value
      • 队列尾增加值 rpushx key value
  • 查询值

    • 通过索引获取单个值 lndex key index
    • 通过索引获取多个值 lrange key start stop
  • 修改值

    • 通过索引修改指定位置的值 lset key index value
  • 删除值

    • 队列头删除并获得值 lpop key
    • 阻塞式表头删除并获得值 blpop key timeout
    • 表尾删除并获得值 rpop key
    • 阻塞式表尾删除并获得值 brpop key timeout
    • 删除指定元素值 lrem key count value 删除key链表中,与value值相同的元素值
    • 删除索引范围外的元素值 ltrim key start stop
  • 操作链表

    • 移动元素 rpoplpush source destination
    • 阻塞式移动元素 brpoplpush source destination
  • 获取链表长度 llen key

list

redis-hash数据类型小结

Published on:
Tags: redis

Redis hash 是一个 string 类型的 field(字段) 和 value(值) 的映射表,hash 特别适合用于存储对象。

  • 新增记录
    • 新增一条 hset key field value
    • 批量新增 hmset key field value [field value field value …]
    • 新增一条记录,唯一性 hsetnx key field value
  • 查询记录
    • 查询一条 hget key field
    • 批量查询 hmget key field [field field]
    • 全表查询 hgetall key
  • 修改记录
    • 值增加指定增幅 hincrby key field increment
    • 值增加指定增幅,浮点数 hincrbyfloat key field increment
  • 删除记录 hdel key field
  • 查询表长 hlen key
  • 查询所有的字段 hkeys key
  • 查询所有的值 hvals key
  • 判断字段是否存在 hexists key field

hash

redis-string数据类型小结

Published on:
Tags: redis

Redis 字符串数据类型的相关命令用于管理 redis 字符串值。

  • 设置值

    • 设置一个键值 set key val
    • 批量设置键值 mset key val [key val …]
    • 设置唯一的键值对 setnx
    • 批量设置唯一的键值对 msetnx
    • 设置新值返回旧值 getset key val
  • 获取值

    • 获取键值 get
    • 批量获取键值 mget
  • 修改值

    • 值增加1 incr key
    • 值增加指定增幅 incrby key increment
    • 值减1 decr key
    • 值减少指定减幅 decrby key decrement
  • 过期时间

    • 设置值和过期时间,【单位秒 setex key seconds value】,【单位毫秒 psetex key milliseconds value】
  • 字符串操作

    • 返回值的子串 getrange key start end
    • 使用子串覆盖值 setrange key offset val
    • 返回值的长度 strlen key
    • 字符串追加到值的后面 append key value

string

redis命令小结

Published on:
Tags: redis

Redis

  • 操作命令

    • 删除指定的key:del key
    • 为给定 key 设置过期时间,以秒计: expire key seconds
    • 指定key在特定的时间戳后过期,以秒计: expireat key timestamp
    • 为给定 key 设置过期时间,以毫秒计: pexpire key milliseconds
    • 指定key在特定的时间戳后过期,以毫秒计: pexpireat key milliseconds-timestamp
    • 将当前数据库的 key 移动到给定的数据库 db 当中:move key db
    • 持久化key:persist key
    • 重命名key:rename key newkey
    • 仅当newkey不存在时,重命名key:renamenx key newkey
  • 查询命令

    • 查找所有符合给定模式的key:keys pattern
    • 查看key的剩余生存时间,以秒计: ttl key
    • 查看key的剩余生存时间,以毫秒计: pttl key
    • 从当前数据库中随机返回一个 key:randomkey
    • 查询key的数据类型:type key
  • 判断命令

    • 检查给定 key 是否存在:exists key

comnamd

THINKPHP6如何实现门面模式

Published on:

THINKPHP6的门面为容器中的(动态)类提供了一个静态调用接口,相比于传统的静态方法调用, 带来了更好的可测试性和扩展性,你可以为任何的非静态类库定义一个facade类。

门面的核心文件是 facade.php ,文件内定义了 facade 类,包含有:

  • 待子类重写的方法 getFacadeClass
  • 实例化子系统类的方法 createFacade
  • 魔术方法__callstatic
facade.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
abstract class facade
{
protected abstract static function getFacadeClass();

protected static function createFacade()
{
$facadeClass = static::getFacadeClass();
include_once "{$facadeClass}.php";
return new $facadeClass();
}

public static function __callstatic($method,$params)
{
call_user_func_array([static::createFacade(),$method],$params);
}
}

当新增一个子系统类时,同时需要新增一个子系统类的门面类,使得子系统类和 facade 类关联起来。

子系统类tets1.php
1
2
3
4
5
6
7
8
<?php
class test1
{
public function index($name)
{
echo "test1,name={$name}";
}
}
子系统门面类test1facade.php
1
2
3
4
5
6
7
8
9
<?php
include_once 'facade.php';
class test1facade extends facade
{
protected static function getFacadeClass()
{
return 'test1';
}
}

客户端不需要直接调用子系统类,而是通过子系统门面类间接调用,并且采用静态调用的方式调用子系统类里的方法。

client.php
1
2
3
4
5
<?php
include 'test1facade.php';
include 'test2facade.php';
echo test1facade::index('Jerry');
echo test2facade::index('Page');

结果输出

1
test1,name=Jerrytest2,name=Page

协变与工厂方法设计模式

Published on:

协变的概念#

协变使子类比父类方法能返回更具体的类型;
通俗点说就是如果某个返回的类型可以由其派生类型替换,那么这个类型就是支持协变的。

协变与工厂方法模式#

工厂方法模式的特点是一个工厂生产一种产品,有多少个产品就需要有多少个工厂。

基类工厂定义了操作方法和返回值,子类工厂继承自基类工厂,并且重写了操作方法,根据具体的工厂返回实际的类型。

以下代码定义了两个产品类(ShoesBasketball,ShoesRunning),
两个工厂子类(FactoryBasketball,FactoryRunning)。

产品类实现自产品接口(Shoes),产品接口定义了一个方法(whoami)。

工厂子类继承自工厂基类(Factory),工厂基类定义了一个操作方法(makeShoes),并且定义了返回值类型(Shoes)。

工厂子类重写方法(makeShoes),并且定义了比父类更加具体的返回值类型。

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
36
37
38
39
40
41
42
43
44
45
<?php
interface Shoes
{
public function whoami();
}

class ShoesBasketball implements Shoes
{
public function whoami()
{
return "I am Basketball shoes.";
}
}

class ShoesRunning implements Shoes
{
public function whoami()
{
return "I am Running shoes.";
}
}

interface Factory
{
public static function makeShoes():Shoes;
}
class FactoryBasketball implements Factory
{
public static function makeShoes():ShoesBasketball
{
return new ShoesBasketball();
}
}
class FactoryRunning implements Factory
{
public static function makeShoes():ShoesRunning
{
return new ShoesRunning();
}
}

$shoes = FactoryBasketball::makeShoes();
echo $shoes->whoami();
$shoes = FactoryRunning::makeShoes();
echo $shoes->whoami();

结果输出

1
I am Basketball shoes.I am Running shoes.

Homebrew -- macOS缺失的软件包的管理器

Published on:
Tags: macOS

Homebrew 是 macOS(或 Linux)缺失的软件包的管理器。

使用 Homebrew 安装 Apple(或您的 Linux 系统)没有预装但 你 需要的东西

安装 Homebrew#

将以下命令粘贴至终端,实现安装。

1
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

Homebrew 类型#

formula#

formula 意思是一些软件包,包含命令行工具、开发库、一些字体、插件等,共性是不提供界面,提供给终端或者是开发者使用。

安装 formula 前可以在 formulae listing页面 搜索目标 formula ,查看 formula 的详情细节,包括安装命令,描述,版本号和安装数量统计等。

cask#

cask 是用户软件,比如 chrome、wechat、qq 这些提供用户交互界面的软件。

同样的,安装 cask 前可以在 casks listing页面 搜索目标 cask ,查看 cask 的详情细节。

casks listing页面 包含了大部分常用的软件:微信、qq、浏览器、笔记、播放器等等。一定程度上可以代替App store。

Homebrew 命令#

常用命令#

命令 作用
brew update 同步远程的 formulae 到本地,更新本地的 formulae 库
brew install formula 安装 formula
brew remove formula 卸载 formula
brew install –cask cask 安装 cask
brew list 查看已安装的包列表
brew list –versions 查看你安装过的包列表(包括版本号)
brew info [formula|cask] 查看[formula|cask]的简要信息
brew upgrade [formula|cask] 升级[formula|cask]

常用软件安装命令#

命令 作用
brew install –cask sublime-text 安装sublime编辑器
brew install –cask qq 安装qq
brew install –cask wechat 安装微信
brew install –cask firefox 安装firefox
brew install –cask chrome-remote-desktop-host 安装chrome
brew install –cask yinxiangbiji 安装印象笔记

其他命令#

命令 作用
brew outdated 列出需要升级的 formulae
brew services 管理后台运行服务工具
brew services [list] (–json): 列出有关当前用户的所有托管服务的信息
brew services info (formula|–all) [–json] 列出当前用户的所有托管服务
brew services start (formula|–all) 马上开启formula服务,并且注册到当前用户的启动进程上
brew services stop (formula|–all) 马上停止formula服务,并且取消注册到当前用户的启动进程上
brew services restart (formula|–all)
brew services run (formula|–all) 运行formula服务,但是并不注册到当前用户的启动进程上

PHP反射机制

Published on:
Tags: php

PHP的反射机制提供了一套反射API,用来访问和使用类、方法、属性、参数和注释等。

比如可以通过一个对象知道这个对象所属的类,这个类包含哪些方法,这些方法需要传入什么参数,每个参数是什么类型等等。

不用创建类的实例也可以访问类的成员和方法,就算类成员定义为 private也可以在外部访问。

官方文档 提供了诸如 ReflectionClass、ReflectionMethod、ReflectionObject、ReflectionExtension 等反射类及相应的API,用得最多的是 ReflectionClass。

ReflectionClass 反射类#

通过 ReflectionClass 反射一个类,参数是类名或者类实例。

通过构造方法实例化类#

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
* Test1 类
*/
class Test1
{
private $id;
public $name;

public function __construct(int $id,string $name)
{
$this->id = $id;
$this->name = $name;
}
public function getId()
{
return $this->id;
}
public function getName()
{
return $this->name;
}

}

Test1 类拥有一个 private 类型的 id 和 一个 public 类型的 name 。

还有一个构造方法和两个普通方法。

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
// 初始化 ReflectionClass 类
function getReflectObject($class)
{
try {
return new ReflectionClass($class);
} catch (ReflectionException $e) {
throw new ClassNotFoundException('class not exists: ' . $class, $class, $e);
}
}

// 实例化类后调用方法
function invokeClass_1(string $class,array $args)
{
$reflect = getReflectObject($class);
// 创建一个类的新实例,给出的参数将传递到类的构造函数。
$object = $reflect->newInstanceArgs($args);

// 获取类的属性,返回ReflectionProperty 对象的数组。
$props = $reflect->getProperties();
foreach ($props as $prop) {
// 输出属性变量名和指定实例的属性值
echo $prop->getName() . "=".$prop->getValue($object)."\n";
}
// 类实例直接调用方法
$name = $object->getName();

return $name;
}

$res = invokeClass_1('Test1',[1,'Jerry']);
var_dump($res);

输出

1
2
3
id=1
name=Jerry
string(5) "Jerry"

通过单例模式实例化类#

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
36
37
38
39
40
41
42
43
44
45
46
/**
* Test2 类
*/
class Test2
{
private $id;
public $name;
private static $_instance;

private function __construct(int $id,string $name)
{
$this->id = $id;
$this->name = $name;
}

// 把构造函数 __construct 改成 private,并增加 getInstance 方法
public static function getInstance(int $id,string $name)
{
if(empty(self::$_instance))
self::$_instance = new static($id,$name);

return self::$_instance;
}

public function getId()
{
return $this->id;
}

public function getName()
{
return $this->name;
}

public static function sayHi($id,$name)
{
return "hello {$name}, your id={$id}.";
}

public static function index()
{
return "hello index";
}

}

Test2 类的构造方法是 private 的,因此外部需要通过静态方法 getInstance 来获得类的实例。

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
// 初始化 ReflectionClass 类
function getReflectObject($class)
{
try {
return new ReflectionClass($class);
} catch (ReflectionException $e) {
throw new ClassNotFoundException('class not exists: ' . $class, $class, $e);
}
}

// 调用静态方法
function invokeClass_2(string $class,array $args)
{
$reflect = getReflectObject($class);
$name = null;
// 检查类中是否存在指定的方法
if ($reflect->hasMethod('getInstance')) {
// 获取一个类方法的 ReflectionMethod。
$method = $reflect->getMethod('getInstance');
if ($method->isPublic() && $method->isStatic()) {
// 使用数组给方法传送参数,并执行他。
$object = $method->invokeArgs(null, $args);
$name = $object->getName();
}
}
return $name;
}

$res = invokeClass_2('Test2',[2,'Sam']);
var_dump($res);

输出

1
string(3) "Sam"

ReflectionMethod 反射类#

ReflectionMethod 类也具有反射一个类的作用。区别是参数需要传递类名和方法名。

调用有参数的方法#

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
// 初始化 ReflectionMethod 类
function getReflectMethodObject($class,$name)
{
try {
return new ReflectionMethod($class,$name);
} catch (ReflectionException $e) {
throw new ClassNotFoundException('class or method not exists: ' . $class, $class, $e);
}
}

// 调用静态方法
function invokeMethod_1(string $class,string $name,array $args)
{
$method = getReflectMethodObject($class,$name);
// 获取方法定义的参数数目,包括可选参数
$num = $method->getNumberOfParameters();
if($num > 0)
// 使用数组给方法传送参数,并执行他。
$res = $method->invokeArgs(null,$args);
else
// 执行一个反射的方法。
$res = $method->invoke(null);

return $res;
}
$res = invokeMethod_1('Test2','sayHi',[2,'Sam']);
var_dump($res);

输出

1
string(21) "hello Sam, your id=2."

以上功能作用与

1
$res = call_user_func_array([__NAMESPACE__.'Test2','sayHi'],[2,'Sam']); 

相似。

调用无参数的方法#

1
2
$res = invokeMethod_1('Test2','index',[]);
var_dump($res);

输出

1
string(11) "hello index"

以上功能作用与

1
$res = call_user_func([__NAMESPACE__.'Test2','index']);

相似。

ReflectionFunction 反射类#

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 一个处理数据的方法
function processUserData($name, $age, $job = "", $hobbie = "")
{
$msg = "Hello $name. You have $age years old";
if (!empty($job)) {
$msg .= ". Your job is $job";
}

if (!empty($hobbie)) {
$msg .= ". Your hobbie is $hobbie";
}

return $msg . ".";
}

$refFunction = new ReflectionFunction('processUserData');
$valuesToProcess = [
'name' => 'Anderson Lucas Silva de Oliveira',
'age' => 21,
'hobbie' => 'Play games'
];
$res = $refFunction->invoke(...$valuesToProcess);
var_dump($res);

输出

1
string(89) "Hello Anderson Lucas Silva de Oliveira. You have 21 years old. Your hobbie is Play games."

一个demo#

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
36
37
38
39
// 通过反射调用函数或者类方法
function invoke($class,$function,$args)
{
if(function_exists($function))
{
$refFunction = new ReflectionFunction($function);
$res = $refFunction->invoke(...$args);
}else{
$reflect = getReflectObject($class);
$constructor = $reflect->getConstructor();
// 构造函数是公有的
if($constructor->isPublic())
{
$object = $reflect->newInstanceArgs($args);
}else if($reflect->hasMethod('getInstance')){
// 当构造函数为 private ,则通过 getInstance 方法获取类的实例
$method = $reflect->getMethod('getInstance');
if ($method->isPublic() && $method->isStatic())
// 使用数组给方法传送参数,并执行他。
$object = $method->invokeArgs(null, $args);

}
$res = $object->$function();
}
return $res;
}

$valuesToProcess = [
'name' => 'Anderson Lucas Silva de Oliveira',
'age' => 21,
'hobbie' => 'Play games'
];

$res = invoke(null,'processUserData',$valuesToProcess);
// $res = invoke('Test1','getName',[2,'Sam']);
// $res = invoke('Test2','getName',[1,'Jerry']);

var_dump($res);

invoke 函数接收3个参数,分别是:类名,方法名/函数名,传参数组。

invoke 函数会首先判断是否存在函数,存在的话则直接传递参数,执行函数;

1
$res = invoke(null,'processUserData',$valuesToProcess);

若不存在对应的函数,则通过反射类反射指定的类。
首先判断构造函数的权限是否为 public ,是的话则通过构造函数实例化类,最后再调用方法;

1
$res = invoke('Test1','getName',[2,'Sam']);

若构造函数的权限不为 public ,则通过判断是否存在 getInstance 方法,并且方法权限为 public 和 static , getInstance 方法体使用单例模式返回类的实例。调用 getInstance 方法得到类的实例,最后调用方法。

1
$res = invoke('Test2','getName',[1,'Jerry']);