ZSH 或称 Z Shell 是一个类似于 Bash 和 SH 的 Linux Shell,它具有一些 Bash 和其它 Shell 不具备的高级功能。流行的 Git 版本控制系统也可以使用插件与 ZSH 很好的集成,这一点对软件开发人员来说非常有用。而且 ZSH 有非常多的主题和插件支持,比 Bash 更具可定制性。简单来说,ZSH 就是一款替代 Bash 且非常好用的 Linux Shell。

Version

Ubuntu 18.04.2 LTS

安装ZSH Shell

ZSH 已经被收录到了 Ubuntu 18.04 LTS 的官方软件包存储库中,安装起来也非常容易。使用如下命令就可以直接安装

1
2
sudo apt update
sudo apt install zsh

阅读全文 »

Version

PHP version 7.1.26

键名是string,两者区别

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
$arr1 = ['a' => 'PHP'];
$arr2 = ['a' => 'PYTHON'];
print_r(array_merge($arr1, $arr2));
// Array ( [a] => PYTHON ) 如果键名为字符,且键名相同,array_merge()后面数组元素值会覆盖前面数组元素值
print_r($arr1 + $arr2);
// Array ( [a] => PHP )如果键名为字符,且键名相同,数组相加会将最先出现的值作为结果

//再比如
$arr1 = ['a' => '1', 'b' => '2'];
$arr2 = ['a' => '1', 'b' => '3', 'c' => '2'];
print_r(array_merge($arr1,$arr2));
// Array ( [a] => 1 [b] => 3 [c] => 2 )
print_r($arr1 + $arr2);
// Array ( [a] => 1 [b] => 2 [c] => 2 )
阅读全文 »

今天是 2018-07-31 执行代码

1
date("Y-m-d",strtotime("-1 month"));

按正常理解输出应该是 2018-06-30,但实际输出是 2018-07-01

虽然这个问题看起来很迷惑,但从内部逻辑上来说呢,其实是”对”的。
我们来模拟下date内部的对于这种事情的处理逻辑:

  1. 先做-1 month,那么当前是07-31,减去一以后就是06-31
  2. 再做日期规范化,因为6月没有31号,所以就好像2点60等于3点一样,6月31就等于了7月1

是不是逻辑很”清晰”呢? 我们也可以手动验证第二个步骤,比如:

1
2
var_dump(date("Y-m-d", strtotime("2017-06-31")));
//输出2017-07-01
阅读全文 »

Version

PHP 7.1.16

最近我在一个项目中使用 empty 时获取到了一些意料之外的结果。下面是我处理后的调试记录,在这里分享给你。

1
2
3
4
var_dump(
$person->firstName,
empty($person->firstName)
);

它的结果是:

1
2
string(5) "Freek"
bool(true)
阅读全文 »

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
47
48
49
/**
* 友好的时间显示
*
* size = 1, 显示1位,如: 1年、3个月、5天、20小时...
* size = 2, 显示2位,如: 1年1个月、1年3天、5天4小时、2小时25分...
* size = 3, 显示3位,如: 1年1个月4天、1年3天20小时、5天4小时3秒、2小时25分10秒...
* size = 4, 显示4位,如: 1年1个月4天16小时...
* size >= 5,显示5位,如: 1年1个月4天16小时15分钟...
*
* @param string|DateTime $datetime 日期字符串或日期 DateTime 对象
* @param int $size 精确到位数
* @param bool $absolute 正数的时间间隔
*
* @return string
*/
public static function friendlyDate($datetime, $size = 1, $absolute = false)
{
if (is_string($datetime)) {
$datetime = new DateTime($datetime);
}

if (! ($datetime instanceof DateTime)) {
throw new \InvalidArgumentException('invalid "DateTime" object');
}

$now = new DateTime();
if ($absolute && $datetime <= $now) {
return '';
}

$interval = $now->diff($datetime);

$intervalData = [
$interval->y, $interval->m, $interval->d,
$interval->h, $interval->i, $interval->s,
];
$intervalFormat = ['年', '个月', '天', '小时', '分钟', '秒'];

foreach ($intervalData as $key => $value) {
if ($value) {
$intervalData[$key] = $value . $intervalFormat[$key];
} else {
unset($intervalData[$key]);
unset($intervalFormat[$key]);
}
}

return implode('', array_slice($intervalData, 0, $size));
}

一道面试题

如果让你用 PHP 生成从 1 到100 万个数值,请问怎么做才能最省内存?

没错,这是一道面试题,如果让你写出答案,你会有什么样的思路呢?请先独自思考几分钟。

可能你想到的会是这种方式:

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
<?php
// 我自己本地测试大概用了 34MB 内存
function makeLargeArray($length){
$dataset = [];
for ($i = 0; $i < $length; $i++) {
$dataset[] = $i;
}
return $dataset;
}
$customRange = makeLargeArray(1000000);
foreach ($customRange as $i) {
echo $i, PHP_EOL;
}

// 记录使用的内存
function formatBytes($bytes, $precision = 2) {
$units = array("b", "kb", "mb", "gb", "tb");

$bytes = max($bytes, 0);
$pow = floor(($bytes ? log($bytes) : 0) / log(1024));
$pow = min($pow, count($units) - 1);

$bytes /= (1 << (10 * $pow));

return round($bytes, $precision) . " " . $units[$pow];
}

print formatBytes(memory_get_peak_usage());

你如果给出这种答案的话,肯定不会让面试官满意的。因为这道题的重点是节省内存,如果是如上的程序,虽然能够实现题目的前半部分要求,但实际运行起来却是一个非常吃内存的老虎。因为从 PHP 底层分析, makeLargeArray() 会预先创建一个由一百万个整数组成的数组分配内存!

那么到底要怎么做才能既节省内存,又能实现这道题的目标呢?

阅读全文 »

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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
#运行用户
user nobody;
#启动进程,通常设置成和cpu的数量相等
worker_processes 1;

#全局错误日志及PID文件
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;

#pid logs/nginx.pid;

#工作模式及连接数上限
events {
#epoll是多路复用IO(I/O Multiplexing)中的一种方式,
#仅用于linux2.6以上内核,可以大大提高nginx的性能
use epoll;

#单个后台worker process进程的最大并发链接数
worker_connections 1024;

# 并发总数是 worker_processes 和 worker_connections 的乘积
# 即 max_clients = worker_processes * worker_connections
# 在设置了反向代理的情况下,max_clients = worker_processes * worker_connections / 4 为什么
# 为什么上面反向代理要除以4,应该说是一个经验值
# 根据以上条件,正常情况下的Nginx Server可以应付的最大连接数为:4 * 8000 = 32000
# worker_connections 值的设置跟物理内存大小有关
# 因为并发受IO约束,max_clients的值须小于系统可以打开的最大文件数
# 而系统可以打开的最大文件数和内存大小成正比,一般1GB内存的机器上可以打开的文件数大约是10万左右
# 我们来看看360M内存的VPS可以打开的文件句柄数是多少:
# $ cat /proc/sys/fs/file-max
# 输出 34336
# 32000 < 34336,即并发连接总数小于系统可以打开的文件句柄总数,这样就在操作系统可以承受的范围之内
# 所以,worker_connections 的值需根据 worker_processes 进程数目和系统可以打开的最大文件总数进行适当地进行设置
# 使得并发总数小于操作系统可以打开的最大文件数目
# 其实质也就是根据主机的物理CPU和内存进行配置
# 当然,理论上的并发总数可能会和实际有所偏差,因为主机还有其他的工作进程需要消耗系统资源。
# ulimit -SHn 65535

}

http {
#设定mime类型,类型由mime.type文件定义
include mime.types;
default_type application/octet-stream;
#设定日志格式
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';

access_log logs/access.log main;

#sendfile 指令指定 nginx 是否调用 sendfile 函数(zero copy 方式)来输出文件,
#对于普通应用,必须设为 on,
#如果用来进行下载等应用磁盘IO重负载应用,可设置为 off,
#以平衡磁盘与网络I/O处理速度,降低系统的uptime.
sendfile on;
#tcp_nopush on;

#连接超时时间
#keepalive_timeout 0;
keepalive_timeout 65;
tcp_nodelay on;

#开启gzip压缩
gzip on;
gzip_disable "MSIE [1-6].";

#设定请求缓冲
client_header_buffer_size 128k;
large_client_header_buffers 4 128k;


#设定虚拟主机配置
server {
#侦听80端口
listen 80;
#定义使用 www.nginx.cn访问
server_name www.nginx.cn;

#定义服务器的默认网站根目录位置
root html;

#设定本虚拟主机的访问日志
access_log logs/nginx.access.log main;

#默认请求
location / {

#定义首页索引文件的名称
index index.php index.html index.htm;

}

# 定义错误提示页面
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}

#静态文件,nginx自己处理
location ~ ^/(images|javascript|js|css|flash|media|static)/ {

#过期30天,静态文件不怎么更新,过期可以设大一点,
#如果频繁更新,则可以设置得小一点。
expires 30d;
}

#PHP 脚本请求全部转发到 FastCGI处理. 使用FastCGI默认配置.
location ~ .php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}

#禁止访问 .htxxx 文件
location ~ /.ht {
deny all;
}

}
}
阅读全文 »

Version

PhpStorm 2017.3.3
Postman 5.5.0
php-7.1.12-Win32-VC14-x64 TS

安装 xdebug 模块

前往 xdebug 官方网站 下载与自己的 PHP 版本匹配的 xdebug模块文件,如果不知道要选择哪个版本的 xdebug,可以在浏览器上查看 phpinfo(),复制全部 phpinfo()这里自动解析。最后,将 xdebug 模块文件放入PHP安装目录/ext文件夹中。

配置 php.ini

php.ini 添加如下几行配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
[xdebug]
;指定Xdebug扩展文件
zend_extension = php_xdebug.dll
xdebug.default_enable = 1
;远程调试
xdebug.remote_enable = on
;自动打开远程调试
xdebug.remote_autostart = 1
;代码自动跟踪
xdebug.auto_trace = off
;收集传递给函数的参数变量
xdebug.collect_params=on
;收集函数调用的返回值
xdebug.collect_return=on
;性能检测分析
xdebug.profiler_enable_trigger = on
;生成的分析文件
xdebug.profiler_output_name = cachegrind.out.%t.%p
;堆栈跟踪文件的存放目录
xdebug.profiler_output_dir = "D:/laragon/tmp"
extension=php_printer.dll
;指定传递给DBGp调试器处理程序的IDE Key 在Chrome以及FireFox中插件配置的时候要用到
xdebug.idekey=PHPSTORM
阅读全文 »

git 没有跟踪空目录,所以需要跟踪那么就需要添加文件,就是在目录下新建一个 .gitkeep 文件(文件名其实随意,不过常见的是 .gitkeep.keep)方法如下:

1
find . -type d -empty -exec touch {}/.gitkeep \;
0%