产品文档PRD的正确打开方式总结

总结zkbhj 发表了文章 • 0 个评论 • 1552 次浏览 • 2016-12-23 15:20 • 来自相关话题

首先、任何项目得沟通都建立在文档得基础上。在任何节点发生需求不明确和需求变更,都必须更新文档。
第一步、理解需求
问三个为什么?为什么这么做?解决什么问题?对业务有什么影响?确保理解需求得目标目的和价值;
 
第二步、心中有方案
整体技术方案思路产出和前端的交互方案,是spa还是mpa?是否前后端分离;和后端系统的交互方案;
 
第三步、产出详细技术方案
先产出接口文档,保证其他团队使用;先产出假接口;方案设计(db,缓存,cdn);
 
第四步、码代码实现
代码分层建设,mvc分层开发;
 
第五步、验证结果
提测之前确保自测通过自测通过以后,读prd,确保一致;
 
  查看全部
首先、任何项目得沟通都建立在文档得基础上。在任何节点发生需求不明确和需求变更,都必须更新文档。
第一步、理解需求
  • 问三个为什么?为什么这么做?解决什么问题?对业务有什么影响?
  • 确保理解需求得目标目的和价值;

 
第二步、心中有方案
  • 整体技术方案思路产出
  • 和前端的交互方案,是spa还是mpa?是否前后端分离;
  • 和后端系统的交互方案;

 
第三步、产出详细技术方案
  • 先产出接口文档,保证其他团队使用;
  • 先产出假接口;
  • 方案设计(db,缓存,cdn);

 
第四步、码代码实现
  • 代码分层建设,mvc分层开发;

 
第五步、验证结果
  • 提测之前确保自测通过
  • 自测通过以后,读prd,确保一致;

 
 

Flex布局:一种实现垂直水平居中的布局方案

回复

前端开发zkbhj 发起了问题 • 1 人关注 • 0 个回复 • 3252 次浏览 • 2016-12-22 17:32 • 来自相关话题

GeoHash算法:将二维的点数据转换成一维的数据

专业名词zkbhj 发表了文章 • 0 个评论 • 2110 次浏览 • 2016-12-22 17:01 • 来自相关话题

1、Geohash的最简单的解释就是:将一个经纬度信息,转换成一个可以排序,可以比较的字符串编码。
 
2、geohash有以下几个特点:
首先,geohash用一个字符串表示经度和纬度两个坐标。某些情况下无法在两列上同时应用索引 (例如MySQL 4之前的版本,Google App Engine的数据层等),利用geohash,只需在一列上应用索引即可。其次,geohash表示的并不是一个点,而是一个矩形区域。比如编码wx4g0ec19,它表示的是一个矩形区域。 使用者可以发布地址编码,既能表明自己位于北海公园附近,又不至于暴露自己的精确坐标,有助于隐私保护。第三,编码的前缀可以表示更大的区域。例如wx4g0ec1,它的前缀wx4g0e表示包含编码wx4g0ec1在内的更大范围。 这个特性可以用于附近地点搜索。首先根据用户当前坐标计算geohash(例如wx4g0ec1)然后取其前缀进行查询 (SELECT * FROM place WHERE geohash LIKE 'wx4g0e%'),即可查询附近的所有地点。

Geohash比直接用经纬度的高效很多。
 
3、编码方式:
  
首先将纬度范围(-90, 90)平分成两个区间(-90,0)、(0, 90),如果目标纬度位于前一个区间,则编码为0,否则编码为1。由于39.92324属于(0, 90),所以取编码为1。
 
然后再将(0, 90)分成 (0, 45), (45, 90)两个区间,而39.92324位于(0, 45),所以编码为0。

以此类推,直到精度符合要求为止,得到纬度编码为1011 1000 1100 0111 1001。 
经度也用同样的算法,对(-180, 180)依次细分,得到116.3906的编码为1101 0010 1100 0100 0100。





 
解码算法与编码算法相反,先进行base32解码,然后分离出经纬度,最后根据二进制编码对经纬度范围进行细分即可,这里不再赘述。
 
PHP实现方式:
<?php
/**
* Geohash generation class
* http://blog.dixo.net/downloads/
*
* This file copyright (C) 2008 Paul Dixon (paul@elphin.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/



/**
* Encode and decode geohashes
*
*/
class Geohash
{
private $coding="0123456789bcdefghjkmnpqrstuvwxyz";
private $codingMap=array();

public function Geohash()
{
//build map from encoding char to 0 padded bitfield
for($i=0; $i<32; $i++)
{
$this->codingMap[substr($this->coding,$i,1)]=str_pad(decbin($i), 5, "0", STR_PAD_LEFT);
}

}

/**
* Decode a geohash and return an array with decimal lat,long in it
*/
public function decode($hash)
{
//decode hash into binary string
$binary="";
$hl=strlen($hash);
for($i=0; $i<$hl; $i++)
{
$binary.=$this->codingMap[substr($hash,$i,1)];
}

//split the binary into lat and log binary strings
$bl=strlen($binary);
$blat="";
$blong="";
for ($i=0; $i<$bl; $i++)
{
if ($i%2)
$blat=$blat.substr($binary,$i,1);
else
$blong=$blong.substr($binary,$i,1);

}

//now concert to decimal
$lat=$this->binDecode($blat,-90,90);
$long=$this->binDecode($blong,-180,180);

//figure out how precise the bit count makes this calculation
$latErr=$this->calcError(strlen($blat),-90,90);
$longErr=$this->calcError(strlen($blong),-180,180);

//how many decimal places should we use? There's a little art to
//this to ensure I get the same roundings as geohash.org
$latPlaces=max(1, -round(log10($latErr))) - 1;
$longPlaces=max(1, -round(log10($longErr))) - 1;

//round it
$lat=round($lat, $latPlaces);
$long=round($long, $longPlaces);

return array($lat,$long);
}


/**
* Encode a hash from given lat and long
*/
public function encode($lat,$long)
{
//how many bits does latitude need?
$plat=$this->precision($lat);
$latbits=1;
$err=45;
while($err>$plat)
{
$latbits++;
$err/=2;
}

//how many bits does longitude need?
$plong=$this->precision($long);
$longbits=1;
$err=90;
while($err>$plong)
{
$longbits++;
$err/=2;
}

//bit counts need to be equal
$bits=max($latbits,$longbits);

//as the hash create bits in groups of 5, lets not
//waste any bits - lets bulk it up to a multiple of 5
//and favour the longitude for any odd bits
$longbits=$bits;
$latbits=$bits;
$addlong=1;
while (($longbits+$latbits)%5 != 0)
{
$longbits+=$addlong;
$latbits+=!$addlong;
$addlong=!$addlong;
}


//encode each as binary string
$blat=$this->binEncode($lat,-90,90, $latbits);
$blong=$this->binEncode($long,-180,180,$longbits);

//merge lat and long together
$binary="";
$uselong=1;
while (strlen($blat)+strlen($blong))
{
if ($uselong)
{
$binary=$binary.substr($blong,0,1);
$blong=substr($blong,1);
}
else
{
$binary=$binary.substr($blat,0,1);
$blat=substr($blat,1);
}
$uselong=!$uselong;
}

//convert binary string to hash
$hash="";
for ($i=0; $i<strlen($binary); $i+=5)
{
$n=bindec(substr($binary,$i,5));
$hash=$hash.$this->coding[$n];
}


return $hash;
}

/**
* What's the maximum error for $bits bits covering a range $min to $max
*/
private function calcError($bits,$min,$max)
{
$err=($max-$min)/2;
while ($bits--)
$err/=2;
return $err;
}

/*
* returns precision of number
* precision of 42 is 0.5
* precision of 42.4 is 0.05
* precision of 42.41 is 0.005 etc
*/
private function precision($number)
{
$precision=0;
$pt=strpos($number,'.');
if ($pt!==false)
{
$precision=-(strlen($number)-$pt-1);
}

return pow(10,$precision)/2;
}


/**
* create binary encoding of number as detailed in http://en.wikipedia.org/wiki/Geohash#Example
* removing the tail recursion is left an exercise for the reader
*/
private function binEncode($number, $min, $max, $bitcount)
{
if ($bitcount==0)
return "";

#echo "$bitcount: $min $max<br>";

//this is our mid point - we will produce a bit to say
//whether $number is above or below this mid point
$mid=($min+$max)/2;
if ($number>$mid)
return "1".$this->binEncode($number, $mid, $max,$bitcount-1);
else
return "0".$this->binEncode($number, $min, $mid,$bitcount-1);
}


/**
* decodes binary encoding of number as detailed in http://en.wikipedia.org/wiki/Geohash#Example
* removing the tail recursion is left an exercise for the reader
*/
private function binDecode($binary, $min, $max)
{
$mid=($min+$max)/2;

if (strlen($binary)==0)
return $mid;

$bit=substr($binary,0,1);
$binary=substr($binary,1);

if ($bit==1)
return $this->binDecode($binary, $mid, $max);
else
return $this->binDecode($binary, $min, $mid);
}
}


?>
4、感性认识:
 
1)GeoHash将二维的经纬度转换成字符串,比如下图展示了北京9个区域的GeoHash字符串,分别是WX4ER,WX4G2、WX4G3等等,每一个字符串代表了某一矩形区域。也就是说,这个矩形区域内所有的点(经纬度坐标)都共享相同的GeoHash字符串,这样既可以保护隐私(只表示大概区域位置而不是具体的点),又比较容易做缓存,比如左上角这个区域内的用户不断发送位置信息请求餐馆数据,由于这些用户的GeoHash字符串都是WX4ER,所以可以把WX4ER当作key,把该区域的餐馆信息当作value来进行缓存,而如果不使用GeoHash的话,由于区域内的用户传来的经纬度是各不相同的,很难做缓存。





 
2)字符串越长,表示的范围越精确。如图所示,5位的编码能表示10平方千米范围的矩形区域,而6位编码能表示更精细的区域(约0.34平方千米)





 
3)字符串相似的表示距离相近(特殊情况后文阐述),这样可以利用字符串的前缀匹配来查询附近的POI信息。如下两个图所示,一个在城区,一个在郊区,城区的GeoHash字符串之间比较相似,郊区的字符串之间也比较相似,而城区和郊区的GeoHash字符串相似程度要低些。
 










 
通过上面的介绍我们知道了GeoHash就是一种将经纬度转换成字符串的方法,并且使得在大部分情况下,字符串前缀匹配越多的距离越近,回到我们的案例,根据所在位置查询来查询附近餐馆时,只需要将所在位置经纬度转换成GeoHash字符串,并与各个餐馆的GeoHash字符串进行前缀匹配,匹配越多的距离越近。
 
5、使用注意点:
1)由于GeoHash是将区域划分为一个个规则矩形,并对每个矩形进行编码,这样在查询附近POI信息时会导致以下问题,比如红色的点是我们的位置,绿色的两个点分别是附近的两个餐馆,但是在查询的时候会发现距离较远餐馆的GeoHash编码与我们一样(因为在同一个GeoHash区域块上),而较近餐馆的GeoHash编码与我们不一致。这个问题往往产生在边界处。





 
解决的思路很简单,我们查询时,除了使用定位点的GeoHash编码进行匹配外,还使用周围8个区域的GeoHash编码,这样可以避免这个问题。

2)我们已经知道现有的GeoHash算法使用的是Peano空间填充曲线,这种曲线会产生突变,造成了编码虽然相似但距离可能相差很大的问题,因此在查询附近餐馆时候,首先筛选GeoHash编码相似的POI点,然后进行实际距离计算。
学习参考文档:http://www.cnblogs.com/dengxinglin/archive/2012/12/14/2817761.html
http://blog.jobbole.com/80633/
  查看全部
1、Geohash的最简单的解释就是:将一个经纬度信息,转换成一个可以排序,可以比较的字符串编码。
 
2、geohash有以下几个特点:
  • 首先,geohash用一个字符串表示经度和纬度两个坐标。某些情况下无法在两列上同时应用索引 (例如MySQL 4之前的版本,Google App Engine的数据层等),利用geohash,只需在一列上应用索引即可。
  • 其次,geohash表示的并不是一个点,而是一个矩形区域。比如编码wx4g0ec19,它表示的是一个矩形区域。 使用者可以发布地址编码,既能表明自己位于北海公园附近,又不至于暴露自己的精确坐标,有助于隐私保护。
  • 第三,编码的前缀可以表示更大的区域。例如wx4g0ec1,它的前缀wx4g0e表示包含编码wx4g0ec1在内的更大范围。 这个特性可以用于附近地点搜索。首先根据用户当前坐标计算geohash(例如wx4g0ec1)然后取其前缀进行查询 (SELECT * FROM place WHERE geohash LIKE 'wx4g0e%'),即可查询附近的所有地点。


Geohash比直接用经纬度的高效很多。
 
3、编码方式:
  
首先将纬度范围(-90, 90)平分成两个区间(-90,0)、(0, 90),如果目标纬度位于前一个区间,则编码为0,否则编码为1。由于39.92324属于(0, 90),所以取编码为1。
 
然后再将(0, 90)分成 (0, 45), (45, 90)两个区间,而39.92324位于(0, 45),所以编码为0。

以此类推,直到精度符合要求为止,得到纬度编码为1011 1000 1100 0111 1001。 
经度也用同样的算法,对(-180, 180)依次细分,得到116.3906的编码为1101 0010 1100 0100 0100。

7178f37ejw1emyk4yfexpj20hj04tmy1.jpg

 
解码算法与编码算法相反,先进行base32解码,然后分离出经纬度,最后根据二进制编码对经纬度范围进行细分即可,这里不再赘述。
 
PHP实现方式:
<?php
/**
* Geohash generation class
* http://blog.dixo.net/downloads/
*
* This file copyright (C) 2008 Paul Dixon (paul@elphin.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/



/**
* Encode and decode geohashes
*
*/
class Geohash
{
private $coding="0123456789bcdefghjkmnpqrstuvwxyz";
private $codingMap=array();

public function Geohash()
{
//build map from encoding char to 0 padded bitfield
for($i=0; $i<32; $i++)
{
$this->codingMap[substr($this->coding,$i,1)]=str_pad(decbin($i), 5, "0", STR_PAD_LEFT);
}

}

/**
* Decode a geohash and return an array with decimal lat,long in it
*/
public function decode($hash)
{
//decode hash into binary string
$binary="";
$hl=strlen($hash);
for($i=0; $i<$hl; $i++)
{
$binary.=$this->codingMap[substr($hash,$i,1)];
}

//split the binary into lat and log binary strings
$bl=strlen($binary);
$blat="";
$blong="";
for ($i=0; $i<$bl; $i++)
{
if ($i%2)
$blat=$blat.substr($binary,$i,1);
else
$blong=$blong.substr($binary,$i,1);

}

//now concert to decimal
$lat=$this->binDecode($blat,-90,90);
$long=$this->binDecode($blong,-180,180);

//figure out how precise the bit count makes this calculation
$latErr=$this->calcError(strlen($blat),-90,90);
$longErr=$this->calcError(strlen($blong),-180,180);

//how many decimal places should we use? There's a little art to
//this to ensure I get the same roundings as geohash.org
$latPlaces=max(1, -round(log10($latErr))) - 1;
$longPlaces=max(1, -round(log10($longErr))) - 1;

//round it
$lat=round($lat, $latPlaces);
$long=round($long, $longPlaces);

return array($lat,$long);
}


/**
* Encode a hash from given lat and long
*/
public function encode($lat,$long)
{
//how many bits does latitude need?
$plat=$this->precision($lat);
$latbits=1;
$err=45;
while($err>$plat)
{
$latbits++;
$err/=2;
}

//how many bits does longitude need?
$plong=$this->precision($long);
$longbits=1;
$err=90;
while($err>$plong)
{
$longbits++;
$err/=2;
}

//bit counts need to be equal
$bits=max($latbits,$longbits);

//as the hash create bits in groups of 5, lets not
//waste any bits - lets bulk it up to a multiple of 5
//and favour the longitude for any odd bits
$longbits=$bits;
$latbits=$bits;
$addlong=1;
while (($longbits+$latbits)%5 != 0)
{
$longbits+=$addlong;
$latbits+=!$addlong;
$addlong=!$addlong;
}


//encode each as binary string
$blat=$this->binEncode($lat,-90,90, $latbits);
$blong=$this->binEncode($long,-180,180,$longbits);

//merge lat and long together
$binary="";
$uselong=1;
while (strlen($blat)+strlen($blong))
{
if ($uselong)
{
$binary=$binary.substr($blong,0,1);
$blong=substr($blong,1);
}
else
{
$binary=$binary.substr($blat,0,1);
$blat=substr($blat,1);
}
$uselong=!$uselong;
}

//convert binary string to hash
$hash="";
for ($i=0; $i<strlen($binary); $i+=5)
{
$n=bindec(substr($binary,$i,5));
$hash=$hash.$this->coding[$n];
}


return $hash;
}

/**
* What's the maximum error for $bits bits covering a range $min to $max
*/
private function calcError($bits,$min,$max)
{
$err=($max-$min)/2;
while ($bits--)
$err/=2;
return $err;
}

/*
* returns precision of number
* precision of 42 is 0.5
* precision of 42.4 is 0.05
* precision of 42.41 is 0.005 etc
*/
private function precision($number)
{
$precision=0;
$pt=strpos($number,'.');
if ($pt!==false)
{
$precision=-(strlen($number)-$pt-1);
}

return pow(10,$precision)/2;
}


/**
* create binary encoding of number as detailed in http://en.wikipedia.org/wiki/Geohash#Example
* removing the tail recursion is left an exercise for the reader
*/
private function binEncode($number, $min, $max, $bitcount)
{
if ($bitcount==0)
return "";

#echo "$bitcount: $min $max<br>";

//this is our mid point - we will produce a bit to say
//whether $number is above or below this mid point
$mid=($min+$max)/2;
if ($number>$mid)
return "1".$this->binEncode($number, $mid, $max,$bitcount-1);
else
return "0".$this->binEncode($number, $min, $mid,$bitcount-1);
}


/**
* decodes binary encoding of number as detailed in http://en.wikipedia.org/wiki/Geohash#Example
* removing the tail recursion is left an exercise for the reader
*/
private function binDecode($binary, $min, $max)
{
$mid=($min+$max)/2;

if (strlen($binary)==0)
return $mid;

$bit=substr($binary,0,1);
$binary=substr($binary,1);

if ($bit==1)
return $this->binDecode($binary, $mid, $max);
else
return $this->binDecode($binary, $min, $mid);
}
}


?>

4、感性认识:
 
1)GeoHash将二维的经纬度转换成字符串,比如下图展示了北京9个区域的GeoHash字符串,分别是WX4ER,WX4G2、WX4G3等等,每一个字符串代表了某一矩形区域。也就是说,这个矩形区域内所有的点(经纬度坐标)都共享相同的GeoHash字符串,这样既可以保护隐私(只表示大概区域位置而不是具体的点),又比较容易做缓存,比如左上角这个区域内的用户不断发送位置信息请求餐馆数据,由于这些用户的GeoHash字符串都是WX4ER,所以可以把WX4ER当作key,把该区域的餐馆信息当作value来进行缓存,而如果不使用GeoHash的话,由于区域内的用户传来的经纬度是各不相同的,很难做缓存。

7178f37ejw1emyk4wbz4bj206i06lt9b.jpg

 
2)字符串越长,表示的范围越精确。如图所示,5位的编码能表示10平方千米范围的矩形区域,而6位编码能表示更精细的区域(约0.34平方千米)

7178f37ejw1emyk4wmjhsj208z065aad.jpg

 
3)字符串相似的表示距离相近(特殊情况后文阐述),这样可以利用字符串的前缀匹配来查询附近的POI信息。如下两个图所示,一个在城区,一个在郊区,城区的GeoHash字符串之间比较相似,郊区的字符串之间也比较相似,而城区和郊区的GeoHash字符串相似程度要低些。
 

7178f37ejw1emyk4wyfg1j206i06lt9b.jpg


7178f37ejw1emyk4xfxhfj206006s0t6.jpg

 
通过上面的介绍我们知道了GeoHash就是一种将经纬度转换成字符串的方法,并且使得在大部分情况下,字符串前缀匹配越多的距离越近,回到我们的案例,根据所在位置查询来查询附近餐馆时,只需要将所在位置经纬度转换成GeoHash字符串,并与各个餐馆的GeoHash字符串进行前缀匹配,匹配越多的距离越近。
 
5、使用注意点:
1)由于GeoHash是将区域划分为一个个规则矩形,并对每个矩形进行编码,这样在查询附近POI信息时会导致以下问题,比如红色的点是我们的位置,绿色的两个点分别是附近的两个餐馆,但是在查询的时候会发现距离较远餐馆的GeoHash编码与我们一样(因为在同一个GeoHash区域块上),而较近餐馆的GeoHash编码与我们不一致。这个问题往往产生在边界处。

7178f37ejw1emyk4zpab1j205l062gm1.jpg

 
解决的思路很简单,我们查询时,除了使用定位点的GeoHash编码进行匹配外,还使用周围8个区域的GeoHash编码,这样可以避免这个问题。

2)我们已经知道现有的GeoHash算法使用的是Peano空间填充曲线,这种曲线会产生突变,造成了编码虽然相似但距离可能相差很大的问题,因此在查询附近餐馆时候,首先筛选GeoHash编码相似的POI点,然后进行实际距离计算。
学习参考文档:http://www.cnblogs.com/dengxinglin/archive/2012/12/14/2817761.html
http://blog.jobbole.com/80633/
 

如何提高工作学习效率之:番茄工作法

总结zkbhj 发表了文章 • 0 个评论 • 1491 次浏览 • 2016-12-22 15:24 • 来自相关话题

1、什么是“番茄工作法”?

    番茄工作法是简单易行的时间管理方法,是由弗朗西斯科·西里洛于1992年创立的一种相对于GTD更微观的时间管理方法。使用番茄工作法,选择一个待完成的任务,将番茄时间设为25分钟,专注工作,中途不允许做任何与该任务无关的事,直到番茄时钟响起,然后在纸上画一个X短暂休息一下(5分钟就行),每4个番茄时段多休息一会儿。番茄工作法极大地提高了工作的效率,还会有意想不到的成就感。
 







2、遵循的原则:

1)一个番茄时间(25分钟)不可分割,不存在半个或一个半番茄时间。
2)一个番茄时间内如果做与任务无关的事情,则该番茄时间作废。
3)永远不要在非工作时间内使用《番茄工作法》。(例如:用3个番茄时间陪儿子下的棋、用5个番茄时间钓鱼,等等。)
4)不要拿自己的番茄数据与他人的番茄数据比较。
5)番茄的数量不可能决定任务最终的成败。
6)必须有一份适合自己的作息时间表。


3、使用方法:

1、每天开始的时候规划今天要完成的几项任务,将任务逐项写在列表里(或记在软件的清单里)
2、设定你的番茄钟(定时器、软件、闹钟等),时间是25分钟。
3、开始完成第一项任务,直到番茄钟响铃或提醒(25分钟到)。
4、停止工作,并在列表里该项任务后画个X。
5、休息3~5分钟,活动、喝水、方便等等。
6、开始下一个番茄钟,继续该任务。一直循环下去,直到完成该任务,并在列表里将该任务划掉。
7、每四个番茄钟后,休息25分钟。

在某个番茄钟的过程里,如果突然想起要做什么事情——

a.非得马上做不可的话,停止这个番茄钟并宣告它作废(哪怕还剩5分钟就结束了),去完成这件事情,之后再重新开始同一个番茄钟;
b.不是必须马上去做的话,在列表里该项任务后面标记一个逗号(表示打扰),并将这件事记在另一个列表里(比如叫“计划外事件”),然后接着完成这个番茄钟。


4、番茄工作法是一套简单的工具和流程,其优点如下:

1、减轻时间焦虑
2、提升集中力和注意力,减少中断
3、增强决策意识
4、唤醒激励和持久激励
5、巩固达成目标的决心
6、完善预估流程,精确地保质保量
7、改进工作学习流程
8、强化决断力,快刀斩乱麻 查看全部
1、什么是“番茄工作法”?

    番茄工作法是简单易行的时间管理方法,是由弗朗西斯科·西里洛于1992年创立的一种相对于GTD更微观的时间管理方法。使用番茄工作法,选择一个待完成的任务,将番茄时间设为25分钟,专注工作,中途不允许做任何与该任务无关的事,直到番茄时钟响起,然后在纸上画一个X短暂休息一下(5分钟就行),每4个番茄时段多休息一会儿。番茄工作法极大地提高了工作的效率,还会有意想不到的成就感。
 

1338032942_9855.PNG



2、遵循的原则:


1)一个番茄时间(25分钟)不可分割,不存在半个或一个半番茄时间。
2)一个番茄时间内如果做与任务无关的事情,则该番茄时间作废。
3)永远不要在非工作时间内使用《番茄工作法》。(例如:用3个番茄时间陪儿子下的棋、用5个番茄时间钓鱼,等等。)
4)不要拿自己的番茄数据与他人的番茄数据比较。
5)番茄的数量不可能决定任务最终的成败。
6)必须有一份适合自己的作息时间表。



3、使用方法:


1、每天开始的时候规划今天要完成的几项任务,将任务逐项写在列表里(或记在软件的清单里)
2、设定你的番茄钟(定时器、软件、闹钟等),时间是25分钟。
3、开始完成第一项任务,直到番茄钟响铃或提醒(25分钟到)。
4、停止工作,并在列表里该项任务后画个X。
5、休息3~5分钟,活动、喝水、方便等等。
6、开始下一个番茄钟,继续该任务。一直循环下去,直到完成该任务,并在列表里将该任务划掉。
7、每四个番茄钟后,休息25分钟。


在某个番茄钟的过程里,如果突然想起要做什么事情——


a.非得马上做不可的话,停止这个番茄钟并宣告它作废(哪怕还剩5分钟就结束了),去完成这件事情,之后再重新开始同一个番茄钟;
b.不是必须马上去做的话,在列表里该项任务后面标记一个逗号(表示打扰),并将这件事记在另一个列表里(比如叫“计划外事件”),然后接着完成这个番茄钟。



4、番茄工作法是一套简单的工具和流程,其优点如下:


1、减轻时间焦虑
2、提升集中力和注意力,减少中断
3、增强决策意识
4、唤醒激励和持久激励
5、巩固达成目标的决心
6、完善预估流程,精确地保质保量
7、改进工作学习流程
8、强化决断力,快刀斩乱麻


Yii2框架:命名空间

Yii框架zkbhj 发表了文章 • 0 个评论 • 1431 次浏览 • 2016-12-20 11:17 • 来自相关话题

命名空间概述
 
(PHP 5 >= 5.3.0, PHP 7)
什么是命名空间?从广义上来说,命名空间是一种封装事物的方法。在很多地方都可以见到这种抽象概念。例如,在操作系统中目录用来将相关文件分组,对于目录中的文件来说,它就扮演了命名空间的角色。具体举个例子,文件foo.txt 可以同时在目录/home/greg 和 /home/other 中存在,但在同一个目录中不能存在两个 foo.txt 文件。另外,在目录 /home/greg 外访问 foo.txt 文件时,我们必须将目录名以及目录分隔符放在文件名之前得到/home/greg/foo.txt。这个原理应用到程序设计领域就是命名空间的概念。
在PHP中,命名空间用来解决在编写类库或应用程序时创建可重用的代码如类或函数时碰到的两类问题:

用户编写的代码与PHP内部的类/函数/常量或第三方类/函数/常量之间的名字冲突。
为很长的标识符名称(通常是为了缓解第一类问题而定义的)创建一个别名(或简短)的名称,提高源代码的可读性。

PHP 命名空间提供了一种将相关的类、函数和常量组合到一起的途径。
 
如何声明?
 
(PHP 5 >= 5.3.0, PHP 7)
虽然任意合法的PHP代码都可以包含在命名空间中,但只有以下类型的代码受命名空间的影响,它们是:类(包括抽象类和traits)、接口、函数和常量。

命名空间通过关键字namespace 来声明。如果一个文件中包含命名空间,它必须在其它所有代码之前声明命名空间,除了一个以外:declare关键字。test1.php
<?php
namespace MyProject;

const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */ }
?>

test2.php
<html>
<?php
namespace MyProject; // 致命错误 - 命名空间必须是程序脚本的第一条语句
?>
 在声明命名空间之前唯一合法的代码是用于定义源文件编码方式的 declare 语句。另外,所有非 PHP 代码包括空白符都不能出现在命名空间的声明之前。另外,与PHP其它的语言特征不同,同一个命名空间可以定义在多个文件中,即允许将同一个命名空间的内容分割存放在不同的文件中。

定义子命名空间

与目录和文件的关系很象,PHP 命名空间也允许指定层次化的命名空间的名称。因此,命名空间的名字可以使用分层次的方式定义:<?php
namespace MyProject\Sub\Level;

const CONNECT_OK = 1; //常量MyProject\Sub\Level\CONNECT_OK
class Connection { /* ... */ } //类 MyProject\Sub\Level\Connection
function connect() { /* ... */ } //函数MyProject\Sub\Level\connect
?>

在同一个文件中定义多个命名空间

也可以在同一个文件中定义多个命名空间。在同一个文件中定义多个命名空间有两种语法形式。
 <?php
namespace MyProject;

const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */ }

namespace AnotherProject;

const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */ }
?>

//不建议使用这种语法在单个文件中定义多个命名空间。建议使用下面的大括号形式的语法

//定义多个命名空间,大括号语法
<?php
namespace MyProject {

const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */ }
}

namespace AnotherProject {

const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */ }
}
?>在实际的编程实践中,非常不提倡在同一个文件中定义多个命名空间。这种方式的主要用于将多个 PHP 脚本合并在同一个文件中。

将全局的非命名空间中的代码与命名空间中的代码组合在一起,只能使用大括号形式的语法。全局代码必须用一个不带名称的 namespace 语句加上大括号括起来。//定义多个命名空间和不包含在命名空间中的代码
<?php
declare(encoding='UTF-8'); //除了开始的declare语句外,命名空间的括号外不得有任何PHP代码。
namespace MyProject {

const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */ }
}

namespace { // global

codesession_start();
$a = MyProject\connect();
echo MyProject\Connection::start();
}
?>
 使用命名空间:基础
 
在讨论如何使用命名空间之前,必须了解 PHP是如何知道要使用哪一个命名空间中的元素的。可以将 PHP命名空间与文件系统作一个简单的类比。在文件系统中访问一个文件有三种方式:
相对文件名形式如foo.txt。它会被解析为currentdirectory/foo.txt,其中 currentdirectory表示当前目录。因此如果当前目录是/home/foo,则该文件名被解析为/home/foo/foo.txt。相对路径名形式如subdirectory/foo.txt。它会被解析为currentdirectory/subdirectory/foo.txt。绝对路径名形式如/main/foo.txt。它会被解析为/main/foo.txt。

PHP 命名空间中的元素使用同样的原理。例如,类名可以通过三种方式引用:
非限定名称,或不包含前缀的类名称,例如 $a=new foo(); 或foo::staticmethod();。如果当前命名空间是currentnamespace,foo 将被解析为currentnamespace\foo。如果使用 foo的代码是全局的,不包含在任何命名空间中的代码,则 foo 会被解析为foo。警告:如果命名空间中的函数或常量未定义,则该非限定的函数名称或常量名称会被解析为全局函数名称或常量名称。限定名称,或包含前缀的名称,例如$a = new subnamespace\foo(); 或subnamespace\foo::staticmethod();。如果当前的命名空间是currentnamespace,则 foo 会被解析为currentnamespace\subnamespace\foo。如果使用 foo 的代码是全局的,不包含在任何命名空间中的代码,foo会被解析为subnamespace\foo。完全限定名称,或包含了全局前缀操作符的名称,例如,$a = new \currentnamespace\foo(); 或 \currentnamespace\foo::staticmethod();。在这种情况下,foo 总是被解析为代码中的文字名(literal name)currentnamespace\foo。
file1.php

<?php
namespace Foo\Bar\subnamespace;

const FOO = 1;
function foo() {}
class foo{
static function staticmethod() {}
}
?>

file2.php

<?php
namespace Foo\Bar;
include 'file1.php';

const FOO = 2;
function foo() {}
class foo{
static function staticmethod() {}
}

/* 非限定名称 */
foo(); // 解析为 Foo\Bar\foo resolves to function Foo\Bar\foo
foo::staticmethod(); // 解析为类 Foo\Bar\foo的静态方法staticmethod。resolves to class Foo\Bar\foo, method staticmethod
echo FOO; // resolves to constant Foo\Bar\FOO

/* 限定名称 */
subnamespace\foo(); // 解析为函数 Foo\Bar\subnamespace\foo
subnamespace\foo::staticmethod(); // 解析为类 Foo\Bar\subnamespace\foo,
// 以及类的方法 staticmethod
echo subnamespace\FOO; // 解析为常量 Foo\Bar\subnamespace\FOO

/* 完全限定名称 */
\Foo\Bar\foo(); // 解析为函数 Foo\Bar\foo
\Foo\Bar\foo::staticmethod(); // 解析为类 Foo\Bar\foo, 以及类的方法 staticmethod
echo \Foo\Bar\FOO; // 解析为常量 Foo\Bar\FOO
?>注意访问任意全局类、函数或常量,都可以使用完全限定名称,例如\strlen() 或\Exception 或\INI_ALL。
 <?php
namespace Foo;

function strlen() {}
const INI_ALL = 3;
class Exception {}

$a = \strlen('hi'); // 调用全局函数
strlen $b = \INI_ALL; // 访问全局常量
INI_ALL $c = new \Exception('error'); // 实例化全局类 Exception
?>


namespace关键字和__NAMESPACE__常量
 
PHP支持两种抽象的访问当前命名空间内部元素的方法,__NAMESPACE__魔术常量和namespace关键字。

常量__NAMESPACE__的值是包含当前命名空间名称的字符串。在全局的,不包括在任何命名空间中的代码,它包含一个空的字符串。
 //__NAMESPACE__ 示例, 在命名空间中的代码
<?php
namespace MyProject;

echo '"', __NAMESPACE__, '"'; // 输出 "MyProject"
?>

//__NAMESPACE__ 示例,全局代码
<?php

echo '"', __NAMESPACE__, '"'; // 输出 " "
?>

//使用__NAMESPACE__动态创建名称
<?php
namespace MyProject;
function get($classname){
$a = __NAMESPACE__ . '\\' . $classname;
return new $a;
}
?>

//namespace操作符,命名空间中的代码
<?php
namespace MyProject;

use blah\blah as mine; // see "Using namespaces: importing/aliasing"
blah\mine(); // calls function MyProject\blah\mine()
namespace\blah\mine(); // calls function MyProject\blah\mine()
namespace\func(); // calls function MyProject\func()
namespace\sub\func(); // calls function MyProject\sub\func()
namespace\cname::method(); // calls static method "method" of class MyProject\cname
$a = new namespace\sub\cname(); // instantiates object of class MyProject\sub\cname
$b = namespace\CONSTANT; // assigns value of constant MyProject\CONSTANT to $b

?>

//namespace操作符, 全局代码
<?php
namespace\func(); // calls function func()
namespace\sub\func(); // calls function sub\func()
namespace\cname::method(); // calls static method "method" of class cname

$a = new namespace\sub\cname(); // instantiates object of class sub\cname
$b = namespace\CONSTANT; // assigns value of constant CONSTANT to $b
?>
 使用命名空间:别名/导入
 
允许通过别名引用或导入外部的完全限定名称,是命名空间的一个重要特征。这有点类似于在类
unix 文件系统中可以创建对其它的文件或目录的符号连接。

所有支持命名空间的PHP版本支持三种别名或导入方式:为类名称使用别名、为接口使用别名或为命名空间名称使用别名。PHP 5.6开始允许导入函数或常量或者为它们设置别名。

在PHP中,别名是通过操作符 use 来实现的.
 //使用use操作符导入/使用别名
<?php
namespace foo;

use My\Full\Classname as Another;
// 下面的例子与 use My\Full\NSname as NSname 相同
use My\Full\NSname;

// 导入一个全局类
use ArrayObject;

// importing a function (PHP 5.6+)
use function My\Full\functionName;

// aliasing a function (PHP 5.6+)
use function My\Full\functionName as func;

// importing a constant (PHP 5.6+)
use const My\Full\CONSTANT;

$obj = new namespace\Another; // 实例化 foo\Another 对象
$obj = new Another; // 实例化 My\Full\Classname 对象
NSname\subns\func(); // 调用函数 My\Full\NSname\subns\func
$a = new ArrayObject(array(1)); // 实例化 ArrayObject 对象
// 如果不使用 "use \ArrayObject" ,则实例化一个 foo\ArrayObject 对象
func(); // calls function My\Full\functionName
echo CONSTANT; // echoes the value of My\Full\CONSTANT
?>注意对命名空间中的名称(包含命名空间分隔符的完全限定名称如 Foo\Bar以及相对的不包含命名空间分隔符的全局名称如 FooBar)来说,前导的反斜杠是不必要的也不推荐的,因为导入的名称必须是完全限定的,不会根据当前的命名空间作相对解析。

为了简化操作,PHP还支持在一行中使用多个use语句。
 //通过use操作符导入/使用别名,一行中包含多个use语句
<?php
use My\Full\Classname as Another, My\Full\NSname;

$obj = new Another; // 实例化 My\Full\Classname 对象
NSname\subns\func(); // 调用函数 My\Full\NSname\subns\func
?>

//导入操作是在编译执行的,但动态的类名称、函数名称或常量名称则不是。
<?php
use My\Full\Classname as Another, My\Full\NSname;

$obj = new Another; // 实例化一个 My\Full\Classname 对象
$a = 'Another';
$obj = new $a; // 实际化一个 Another 对象
?>

//另外,导入操作只影响非限定名称和限定名称。完全限定名称由于是确定的,故不受导入的影响。
<?php
use My\Full\Classname as Another, My\Full\NSname;

$obj = new Another; // instantiates object of class My\Full\Classname
$obj = new \Another; // instantiates object of class Another
$obj = new Another\thing; // instantiates object of class My\Full\Classname\thing
$obj = new \Another\thing; // instantiates object of class Another\thing
?>
 全局空间

如果没有定义任何命名空间,所有的类与函数的定义都是在全局空间,与 PHP 引入命名空间概念前一样。在名称前加上前缀 '\'表示该名称是全局空间中的名称,即使该名称位于其它的命名空间中时也是如此。<?php
namespace A\B\C;

/* 这个函数是 A\B\C\fopen */
function fopen() {
/* ... */
$f = \fopen(...); // 调用全局的fopen函数
return $f;
}
?>

名称解析规则​
 
命名空间名称定义
非限定名称Unqualified name:名称中不包含命名空间分隔符的标识符,例如 Foo限定名称Qualified name:名称中含有命名空间分隔符的标识符,例如 Foo\Bar完全限定名称Fully qualified name:称中包含命名空间分隔符,并以命名空间分隔符开始的标识符,例如 \Foo\Bar。 namespace\Foo 也是一个完全限定名称。

名称解析遵循下列规则:

对完全限定名称的函数,类和常量的调用在编译时解析。例如 new \A\B 解析为类 A\B。

所有的非限定名称和限定名称(非完全限定名称)根据当前的导入规则在编译时进行转换。例如,如果命名空间A\B\C 被导入为 C,那么对 C\D\e() 的调用就会被转换为 A\B\C\D\e()。

在命名空间内部,所有的没有根据导入规则转换的限定名称均会在其前面加上当前的命名空间名称。例如,在命名空间 A\B 内部调用 C\D\e(),则 C\D\e() 会被转换为 A\B\C\D\e() 。
非限定类名根据当前的导入规则在编译时转换(用全名代替短的导入名称)。例如,如果命名空间A\B\C 导入为C,则 new C()被转换为 new A\B\C() 。
在命名空间内部(例如A\B),对非限定名称的函数调用是在运行时解析的。例如对函数foo() 的调用是这样解析的:

在当前命名空间中查找名为 A\B\foo() 的函数
尝试查找并调用 全局(global) 空间中的函数 foo()。

在命名空间(例如A\B)内部对非限定名称或限定名称类(非完全限定名称)的调用是在运行时解析的。下面是调用new C() 及 new D\E() 的解析过程:

new C()的解析:

在当前命名空间中查找A\B\C类。
尝试自动装载类A\B\C。

new D\E()*的解析:

在类名称前面加上当前命名空间名称变成:A\B\D\E,然后查找该类。
尝试自动装载类 A\B\D\E。

为了引用全局命名空间中的全局类,必须使用完全限定名称 new \C()。<?php
namespace A;
use B\D, C\E as F;

// 函数调用
foo(); // 首先尝试调用定义在命名空间"A"中的函数foo()
// 再尝试调用全局函数 "foo"

\foo(); // 调用全局空间函数 "foo"

my\foo(); // 调用定义在命名空间"A\my"中函数 "foo"

F(); // 首先尝试调用定义在命名空间"A"中的函数 "F"
// 再尝试调用全局函数 "F"

// 类引用
new B(); // 创建命名空间 "A" 中定义的类 "B" 的一个对象
// 如果未找到,则尝试自动装载类 "A\B"

new D(); // 使用导入规则,创建命名空间 "B" 中定义的类 "D" 的一个对象
// 如果未找到,则尝试自动装载类 "B\D"

new F(); // 使用导入规则,创建命名空间 "C" 中定义的类 "E" 的一个对象
// 如果未找到,则尝试自动装载类 "C\E"

new \B(); // 创建定义在全局空间中的类 "B" 的一个对象
// 如果未发现,则尝试自动装载类 "B"

new \D(); // 创建定义在全局空间中的类 "D" 的一个对象
// 如果未发现,则尝试自动装载类 "D"

new \F(); // 创建定义在全局空间中的类 "F" 的一个对象
// 如果未发现,则尝试自动装载类 "F"

// 调用另一个命名空间中的静态方法或命名空间函数

B\foo(); // 调用命名空间 "A\B" 中函数 "foo"

B::foo(); // 调用命名空间 "A" 中定义的类 "B" 的 "foo" 方法
// 如果未找到类 "A\B" ,则尝试自动装载类 "A\B"

D::foo(); // 使用导入规则,调用命名空间 "B" 中定义的类 "D" 的 "foo" 方法
// 如果类 "B\D" 未找到,则尝试自动装载类 "B\D"

\B\foo(); // 调用命名空间 "B" 中的函数 "foo"

\B::foo(); // 调用全局空间中的类 "B" 的 "foo" 方法
// 如果类 "B" 未找到,则尝试自动装载类 "B"

// 当前命名空间中的静态方法或函数

A\B::foo(); // 调用命名空间 "A\A" 中定义的类 "B" 的 "foo" 方法
// 如果类 "A\A\B" 未找到,则尝试自动装载类 "A\A\B"

\A\B::foo(); // 调用命名空间 "A\B" 中定义的类 "B" 的 "foo" 方法
// 如果类 "A\B" 未找到,则尝试自动装载类 "A\B"
?>
文/洞房花猪(简书作者)
原文链接:http://www.jianshu.com/p/9e01d16a2e1c
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。
  查看全部
命名空间概述
 
(PHP 5 >= 5.3.0, PHP 7)
什么是命名空间?从广义上来说,命名空间是一种封装事物的方法。在很多地方都可以见到这种抽象概念。例如,在操作系统中目录用来将相关文件分组,对于目录中的文件来说,它就扮演了命名空间的角色。具体举个例子,文件foo.txt 可以同时在目录/home/greg 和 /home/other 中存在,但在同一个目录中不能存在两个 foo.txt 文件。另外,在目录 /home/greg 外访问 foo.txt 文件时,我们必须将目录名以及目录分隔符放在文件名之前得到/home/greg/foo.txt。这个原理应用到程序设计领域就是命名空间的概念。
在PHP中,命名空间用来解决在编写类库或应用程序时创建可重用的代码如类或函数时碰到的两类问题:

用户编写的代码与PHP内部的类/函数/常量或第三方类/函数/常量之间的名字冲突。
为很长的标识符名称(通常是为了缓解第一类问题而定义的)创建一个别名(或简短)的名称,提高源代码的可读性。

PHP 命名空间提供了一种将相关的类、函数和常量组合到一起的途径。
 
如何声明?
 
(PHP 5 >= 5.3.0, PHP 7)
虽然任意合法的PHP代码都可以包含在命名空间中,但只有以下类型的代码受命名空间的影响,它们是:类(包括抽象类和traits)、接口、函数和常量。

命名空间通过关键字namespace 来声明。如果一个文件中包含命名空间,它必须在其它所有代码之前声明命名空间,除了一个以外:declare关键字。
test1.php
<?php
namespace MyProject;

const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */ }
?>

test2.php
<html>
<?php
namespace MyProject; // 致命错误 - 命名空间必须是程序脚本的第一条语句
?>

 在声明命名空间之前唯一合法的代码是用于定义源文件编码方式的 declare 语句。另外,所有非 PHP 代码包括空白符都不能出现在命名空间的声明之前。另外,与PHP其它的语言特征不同,同一个命名空间可以定义在多个文件中,即允许将同一个命名空间的内容分割存放在不同的文件中。

定义子命名空间

与目录和文件的关系很象,PHP 命名空间也允许指定层次化的命名空间的名称。因此,命名空间的名字可以使用分层次的方式定义:
<?php
namespace MyProject\Sub\Level;

const CONNECT_OK = 1; //常量MyProject\Sub\Level\CONNECT_OK
class Connection { /* ... */ } //类 MyProject\Sub\Level\Connection
function connect() { /* ... */ } //函数MyProject\Sub\Level\connect
?>

在同一个文件中定义多个命名空间

也可以在同一个文件中定义多个命名空间。在同一个文件中定义多个命名空间有两种语法形式。
 
<?php
namespace MyProject;

const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */ }

namespace AnotherProject;

const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */ }
?>

//不建议使用这种语法在单个文件中定义多个命名空间。建议使用下面的大括号形式的语法

//定义多个命名空间,大括号语法
<?php
namespace MyProject {

const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */ }
}

namespace AnotherProject {

const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */ }
}
?>
在实际的编程实践中,非常不提倡在同一个文件中定义多个命名空间。这种方式的主要用于将多个 PHP 脚本合并在同一个文件中。

将全局的非命名空间中的代码与命名空间中的代码组合在一起,只能使用大括号形式的语法。全局代码必须用一个不带名称的 namespace 语句加上大括号括起来。
//定义多个命名空间和不包含在命名空间中的代码
<?php
declare(encoding='UTF-8'); //除了开始的declare语句外,命名空间的括号外不得有任何PHP代码。
namespace MyProject {

const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */ }
}

namespace { // global

codesession_start();
$a = MyProject\connect();
echo MyProject\Connection::start();
}
?>

 使用命名空间:基础
 
在讨论如何使用命名空间之前,必须了解 PHP是如何知道要使用哪一个命名空间中的元素的。可以将 PHP命名空间与文件系统作一个简单的类比。在文件系统中访问一个文件有三种方式:
  1. 相对文件名形式如foo.txt。它会被解析为currentdirectory/foo.txt,其中 currentdirectory表示当前目录。因此如果当前目录是/home/foo,则该文件名被解析为/home/foo/foo.txt。
  2. 相对路径名形式如subdirectory/foo.txt。它会被解析为currentdirectory/subdirectory/foo.txt。
  3. 绝对路径名形式如/main/foo.txt。它会被解析为/main/foo.txt。


PHP 命名空间中的元素使用同样的原理。例如,类名可以通过三种方式引用:
  1. 非限定名称,或不包含前缀的类名称,例如 $a=new foo(); 或foo::staticmethod();。如果当前命名空间是currentnamespace,foo 将被解析为currentnamespace\foo。如果使用 foo的代码是全局的,不包含在任何命名空间中的代码,则 foo 会被解析为foo。警告:如果命名空间中的函数或常量未定义,则该非限定的函数名称或常量名称会被解析为全局函数名称或常量名称。
  2. 限定名称,或包含前缀的名称,例如$a = new subnamespace\foo(); 或subnamespace\foo::staticmethod();。如果当前的命名空间是currentnamespace,则 foo 会被解析为currentnamespace\subnamespace\foo。如果使用 foo 的代码是全局的,不包含在任何命名空间中的代码,foo会被解析为subnamespace\foo。
  3. 完全限定名称,或包含了全局前缀操作符的名称,例如,$a = new \currentnamespace\foo(); 或 \currentnamespace\foo::staticmethod();。在这种情况下,foo 总是被解析为代码中的文字名(literal name)currentnamespace\foo。

file1.php

<?php
namespace Foo\Bar\subnamespace;

const FOO = 1;
function foo() {}
class foo{
static function staticmethod() {}
}
?>

file2.php

<?php
namespace Foo\Bar;
include 'file1.php';

const FOO = 2;
function foo() {}
class foo{
static function staticmethod() {}
}

/* 非限定名称 */
foo(); // 解析为 Foo\Bar\foo resolves to function Foo\Bar\foo
foo::staticmethod(); // 解析为类 Foo\Bar\foo的静态方法staticmethod。resolves to class Foo\Bar\foo, method staticmethod
echo FOO; // resolves to constant Foo\Bar\FOO

/* 限定名称 */
subnamespace\foo(); // 解析为函数 Foo\Bar\subnamespace\foo
subnamespace\foo::staticmethod(); // 解析为类 Foo\Bar\subnamespace\foo,
// 以及类的方法 staticmethod
echo subnamespace\FOO; // 解析为常量 Foo\Bar\subnamespace\FOO

/* 完全限定名称 */
\Foo\Bar\foo(); // 解析为函数 Foo\Bar\foo
\Foo\Bar\foo::staticmethod(); // 解析为类 Foo\Bar\foo, 以及类的方法 staticmethod
echo \Foo\Bar\FOO; // 解析为常量 Foo\Bar\FOO
?>
注意访问任意全局类、函数或常量,都可以使用完全限定名称,例如\strlen() 或\Exception 或\INI_ALL。
 
<?php
namespace Foo;

function strlen() {}
const INI_ALL = 3;
class Exception {}

$a = \strlen('hi'); // 调用全局函数
strlen $b = \INI_ALL; // 访问全局常量
INI_ALL $c = new \Exception('error'); // 实例化全局类 Exception
?>


namespace关键字和__NAMESPACE__常量
 
PHP支持两种抽象的访问当前命名空间内部元素的方法,__NAMESPACE__魔术常量和namespace关键字。

常量__NAMESPACE__的值是包含当前命名空间名称的字符串。在全局的,不包括在任何命名空间中的代码,它包含一个空的字符串。
 
//__NAMESPACE__ 示例, 在命名空间中的代码
<?php
namespace MyProject;

echo '"', __NAMESPACE__, '"'; // 输出 "MyProject"
?>

//__NAMESPACE__ 示例,全局代码
<?php

echo '"', __NAMESPACE__, '"'; // 输出 " "
?>

//使用__NAMESPACE__动态创建名称
<?php
namespace MyProject;
function get($classname){
$a = __NAMESPACE__ . '\\' . $classname;
return new $a;
}
?>

//namespace操作符,命名空间中的代码
<?php
namespace MyProject;

use blah\blah as mine; // see "Using namespaces: importing/aliasing"
blah\mine(); // calls function MyProject\blah\mine()
namespace\blah\mine(); // calls function MyProject\blah\mine()
namespace\func(); // calls function MyProject\func()
namespace\sub\func(); // calls function MyProject\sub\func()
namespace\cname::method(); // calls static method "method" of class MyProject\cname
$a = new namespace\sub\cname(); // instantiates object of class MyProject\sub\cname
$b = namespace\CONSTANT; // assigns value of constant MyProject\CONSTANT to $b

?>

//namespace操作符, 全局代码
<?php
namespace\func(); // calls function func()
namespace\sub\func(); // calls function sub\func()
namespace\cname::method(); // calls static method "method" of class cname

$a = new namespace\sub\cname(); // instantiates object of class sub\cname
$b = namespace\CONSTANT; // assigns value of constant CONSTANT to $b
?>

 使用命名空间:别名/导入
 
允许通过别名引用或导入外部的完全限定名称,是命名空间的一个重要特征。这有点类似于在类
unix 文件系统中可以创建对其它的文件或目录的符号连接。

所有支持命名空间的PHP版本支持三种别名或导入方式:为类名称使用别名、为接口使用别名或为命名空间名称使用别名。PHP 5.6开始允许导入函数或常量或者为它们设置别名。

在PHP中,别名是通过操作符 use 来实现的.
 
//使用use操作符导入/使用别名
<?php
namespace foo;

use My\Full\Classname as Another;
// 下面的例子与 use My\Full\NSname as NSname 相同
use My\Full\NSname;

// 导入一个全局类
use ArrayObject;

// importing a function (PHP 5.6+)
use function My\Full\functionName;

// aliasing a function (PHP 5.6+)
use function My\Full\functionName as func;

// importing a constant (PHP 5.6+)
use const My\Full\CONSTANT;

$obj = new namespace\Another; // 实例化 foo\Another 对象
$obj = new Another; // 实例化 My\Full\Classname 对象
NSname\subns\func(); // 调用函数 My\Full\NSname\subns\func
$a = new ArrayObject(array(1)); // 实例化 ArrayObject 对象
// 如果不使用 "use \ArrayObject" ,则实例化一个 foo\ArrayObject 对象
func(); // calls function My\Full\functionName
echo CONSTANT; // echoes the value of My\Full\CONSTANT
?>
注意对命名空间中的名称(包含命名空间分隔符的完全限定名称如 Foo\Bar以及相对的不包含命名空间分隔符的全局名称如 FooBar)来说,前导的反斜杠是不必要的也不推荐的,因为导入的名称必须是完全限定的,不会根据当前的命名空间作相对解析。

为了简化操作,PHP还支持在一行中使用多个use语句。
 
//通过use操作符导入/使用别名,一行中包含多个use语句
<?php
use My\Full\Classname as Another, My\Full\NSname;

$obj = new Another; // 实例化 My\Full\Classname 对象
NSname\subns\func(); // 调用函数 My\Full\NSname\subns\func
?>

//导入操作是在编译执行的,但动态的类名称、函数名称或常量名称则不是。
<?php
use My\Full\Classname as Another, My\Full\NSname;

$obj = new Another; // 实例化一个 My\Full\Classname 对象
$a = 'Another';
$obj = new $a; // 实际化一个 Another 对象
?>

//另外,导入操作只影响非限定名称和限定名称。完全限定名称由于是确定的,故不受导入的影响。
<?php
use My\Full\Classname as Another, My\Full\NSname;

$obj = new Another; // instantiates object of class My\Full\Classname
$obj = new \Another; // instantiates object of class Another
$obj = new Another\thing; // instantiates object of class My\Full\Classname\thing
$obj = new \Another\thing; // instantiates object of class Another\thing
?>

 全局空间

如果没有定义任何命名空间,所有的类与函数的定义都是在全局空间,与 PHP 引入命名空间概念前一样。在名称前加上前缀 '\'表示该名称是全局空间中的名称,即使该名称位于其它的命名空间中时也是如此。
<?php
namespace A\B\C;

/* 这个函数是 A\B\C\fopen */
function fopen() {
/* ... */
$f = \fopen(...); // 调用全局的fopen函数
return $f;
}
?>

名称解析规则​
 
命名空间名称定义
  • 非限定名称Unqualified name:名称中不包含命名空间分隔符的标识符,例如 Foo
  • 限定名称Qualified name:名称中含有命名空间分隔符的标识符,例如 Foo\Bar
  • 完全限定名称Fully qualified name:称中包含命名空间分隔符,并以命名空间分隔符开始的标识符,例如 \Foo\Bar。 namespace\Foo 也是一个完全限定名称。


名称解析遵循下列规则:

对完全限定名称的函数,类和常量的调用在编译时解析。例如 new \A\B 解析为类 A\B。

所有的非限定名称和限定名称(非完全限定名称)根据当前的导入规则在编译时进行转换。例如,如果命名空间A\B\C 被导入为 C,那么对 C\D\e() 的调用就会被转换为 A\B\C\D\e()。

在命名空间内部,所有的没有根据导入规则转换的限定名称均会在其前面加上当前的命名空间名称。例如,在命名空间 A\B 内部调用 C\D\e(),则 C\D\e() 会被转换为 A\B\C\D\e() 。
非限定类名根据当前的导入规则在编译时转换(用全名代替短的导入名称)。例如,如果命名空间A\B\C 导入为C,则 new C()被转换为 new A\B\C() 。
在命名空间内部(例如A\B),对非限定名称的函数调用是在运行时解析的。例如对函数foo() 的调用是这样解析的:

在当前命名空间中查找名为 A\B\foo() 的函数
尝试查找并调用 全局(global) 空间中的函数 foo()。

在命名空间(例如A\B)内部对非限定名称或限定名称类(非完全限定名称)的调用是在运行时解析的。下面是调用new C() 及 new D\E() 的解析过程:

new C()的解析:

在当前命名空间中查找A\B\C类。
尝试自动装载类A\B\C。

new D\E()*的解析:

在类名称前面加上当前命名空间名称变成:A\B\D\E,然后查找该类。
尝试自动装载类 A\B\D\E。

为了引用全局命名空间中的全局类,必须使用完全限定名称 new \C()。
<?php
namespace A;
use B\D, C\E as F;

// 函数调用
foo(); // 首先尝试调用定义在命名空间"A"中的函数foo()
// 再尝试调用全局函数 "foo"

\foo(); // 调用全局空间函数 "foo"

my\foo(); // 调用定义在命名空间"A\my"中函数 "foo"

F(); // 首先尝试调用定义在命名空间"A"中的函数 "F"
// 再尝试调用全局函数 "F"

// 类引用
new B(); // 创建命名空间 "A" 中定义的类 "B" 的一个对象
// 如果未找到,则尝试自动装载类 "A\B"

new D(); // 使用导入规则,创建命名空间 "B" 中定义的类 "D" 的一个对象
// 如果未找到,则尝试自动装载类 "B\D"

new F(); // 使用导入规则,创建命名空间 "C" 中定义的类 "E" 的一个对象
// 如果未找到,则尝试自动装载类 "C\E"

new \B(); // 创建定义在全局空间中的类 "B" 的一个对象
// 如果未发现,则尝试自动装载类 "B"

new \D(); // 创建定义在全局空间中的类 "D" 的一个对象
// 如果未发现,则尝试自动装载类 "D"

new \F(); // 创建定义在全局空间中的类 "F" 的一个对象
// 如果未发现,则尝试自动装载类 "F"

// 调用另一个命名空间中的静态方法或命名空间函数

B\foo(); // 调用命名空间 "A\B" 中函数 "foo"

B::foo(); // 调用命名空间 "A" 中定义的类 "B" 的 "foo" 方法
// 如果未找到类 "A\B" ,则尝试自动装载类 "A\B"

D::foo(); // 使用导入规则,调用命名空间 "B" 中定义的类 "D" 的 "foo" 方法
// 如果类 "B\D" 未找到,则尝试自动装载类 "B\D"

\B\foo(); // 调用命名空间 "B" 中的函数 "foo"

\B::foo(); // 调用全局空间中的类 "B" 的 "foo" 方法
// 如果类 "B" 未找到,则尝试自动装载类 "B"

// 当前命名空间中的静态方法或函数

A\B::foo(); // 调用命名空间 "A\A" 中定义的类 "B" 的 "foo" 方法
// 如果类 "A\A\B" 未找到,则尝试自动装载类 "A\A\B"

\A\B::foo(); // 调用命名空间 "A\B" 中定义的类 "B" 的 "foo" 方法
// 如果类 "A\B" 未找到,则尝试自动装载类 "A\B"
?>

文/洞房花猪(简书作者)
原文链接:http://www.jianshu.com/p/9e01d16a2e1c
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。
 

MySQL datetime数据类型如何设置当前时间为默认值?

回复

数据库zkbhj 回复了问题 • 1 人关注 • 1 个回复 • 3207 次浏览 • 2016-12-20 11:06 • 来自相关话题

Nginx+FPM结构模型剖析及优化

服务器zkbhj 发表了文章 • 0 个评论 • 1583 次浏览 • 2016-12-20 10:28 • 来自相关话题

    随着php脚本语言使用的普及,目前webserice服务大部分都在用nginx+(php-fpm)的结构,了解了其工作过程后才可以在各个方面想办法做调整优化和故障排查,从以下几点总结一下这种模型。
 






 
一、nginx和php-fpm的关系和分工
 
nginx是web服务器,php-fpm是一个PHPFastCGI进程管理器,两者遵循fastcgi的协议进行通信,nginx负责静态类似html文件的处理,php-fpm负责php脚本语言的执行,这么设计的目的是为了解耦前端nginx和后端的php,不至于让容易出问题的php脚本堵塞整个nginx的业务处理,影响用户体验,因为php脚本语言的执行是会比较容易出问题的。nginx之所以能处理成千上万高并发业务,除其本身的异步非阻塞模式,在与和其他模块的耦合扩展方法也是分不开的,在nginx的设计里不能接受的就是阻塞,不过并非完全没有梗,比如说用到的最多的多进程单线程的模式,由于nginx日志没有单独的处理进程,如果收集日志时处理不当就会把worker进程堵死。
 
对应nginx+php-fpm的模型结构图如下:





 
1、nginx的工作简介

接到php的脚本请求后,nginx通过fastcgi_pass指令将请求传递给后端php-fpm的worker进程处理,在此过程中,nginx做了各种超时机制、缓存机制、buffer机制和长连接机制等来保障与后端的php-fpm能够良性高效的合作。

在超时机制方面控制nginx对后端php的等待时间,通过各种timeout指令进行控制,例如:
 fastcgi_connect_timeout : 后端链接时间
fastcgi_send_timeout : 数据发送时间,两次成功发送时间差,不是整个发送时间
fastcgi_read_timeout : 数据接收时间,两次成功接收时间差,不是整个接收时间
当超时后会返回504超时的状态码,在buffer机制指令也有很多,例如:
 fastcgi_buffer_size 存放fastcgi传过来的响应头,一般设置为分页大小
fastcgi_buffers 存放fastcgi传过来的相应内容,一般设置分页的倍数,格式例如 8 4k|8k另外还有一些其它的缓存、长连接机制不做介绍,当设置不合理时也会出现5XX错误,nginx的文章介绍写了有很多的,不再做过多的说明。
 
2、php-fpm工作介绍
 
Php-fpm是一个PHPfastcgi进程管理器,在启动后会有master和worker两种进程,master负责接收外部信号和管理worker进程,worker进程是负责干活的,处理nginx传过来的任务。
master进程只有一个,负责监听端口和管理worker进程,每次传来任务,与前端的nginx建立3次握手后放入连接队列,供worker进程进行accept,当worker进程出现错误或执行超时时,负责将worker进程重启或者杀掉,是php-fpm模型中的大内总管。
Worker进程是工作进程,每个worker进程都独立的执行php程序脚本,然后把执行的结果通过fastcgi协议交给nginx,执行过程中受master的管理。在工作中,worker进程去竞争accept管理进程master的链接队列,accept函数将从连接请求队列中获得连接信息,创建新的socket,并返回该套接字的fd,新创建的socket用于服务器与nginx的通信,而原来的套接字仍然处于监听状态。
php-fpm可以配置多个pool,所有pool由master统一管理监听不同端口并分配不同worker进程池,worker进程池支持动态prefork同时也支持静态开启,服务器内存较大时建议直接计算后配置静态资源池,可以减少频繁prefork进程所带来的开销,提高服务质量,由于进程模型越跑程序耗费越大,因为每个worker进程可以配置执行多少个请求后进行重启,对应的池子的指令和执行多少个请求的指令如下:
 pm = static | dynamic | ondemand :静态池、服务优先、内存优先
pm.max_children = 256 : 开启的最大php进程数
pm.max_requests = 1024 : 在执行了1024个请求后重启worker进程
这也是我们线上服务器的配置,我们线上用的web服务的机器是12核cpu、16G内存,nginx开启12个worker进程,php开启256个进程,跑起来后每个进程大概占用30M内存,也就是(256+12)*30=8G ,另外还跑了一些配管、监控、统计、日志收集等七七八八的软件,整体业务是比较轻松的,这种静态池的配置**减少了prefork进程带来的开销,RT时间100ms以内的占到90%以上(这个与程序写的如何有关),运行一段时间后的开销截图如下:
 
 





 
二、此模型结构常见的5XX服务器端错误及优化
 
1、nginx日志里产生502错误

第一种情况,php-fpm的worker进程执行php程序脚本时,超过了配置的最长执行时间,master进程将worker进程杀掉,直接返回502。返回502后nginx对应的error日志是104: Connection reset by peer,对应的php执行时间的配置如下,一些版本中php-fpm的配置会覆盖php.ini的配置,使php.ini的配置不起作用:php.ini中默认30s:max_execution_time =
php-fpm中:request_terminate_timeout =
第二种情况,连接请求数(accpet之前)超出了端口所能监听的tcp连接的最大值(backlog的值),进不了fpm等待accept的链接队列,直接返回502,这里可能会产生tcp重传;返回502后nginx对应的error日志是111: Connection refused, backlog的值是半连接和全连接的总和,他的存在也有短时间缓冲解耦nginx请求与fpm处理的作用,半连接指收到了syn请求,3次握手尚未建立,全连接指的是3次握手已经成功,不过尚未被accpet的请求,fpm里面有调节的参数,如果fpm的参数设置为-1,则默认走的是系统内核参数net.core.somaxconn的设置值,如果不设置可以在/proc/sys/net/core/somaxconn里查看,默认值是128,所以在连接请求较高的业务里要增大这个值。

第三种情况,网络卡时,客户端断开连接,nginx处显示499,然后php检查到前端nginx产生abort后,又master结束此条任务的继而产生502,一般此种情况的报警,先是499,过会儿变成502,再过一会变成504.

减少避免502报错优化建议

502主要从php-fpm的配置方考虑,根据服务器情况,适量增大php-fpm的工作进程数,适当增加php的执行时间,适当增加backlog值。

php的工作进程数也不是越大越好,这种进程模型运行时间长了占的内存会增大,一般一个php进程是占到30M左右的内存,开多少合适自己算吧,nginx的worker进程一般也能跑到30M的内存,综合计算一下;php的执行时间可以根据你的服务标准来设定,超过服务时间浏览器返回的是502错误,这个按照实际的情况处理吧,反正我是觉得执行的慢有返回结果总比直接返回502错误的强;至于backlog值,当程序写的比较好时,建议设置其数量为php工作进程的1到2倍。
 
2、nginx日志里产生504错误

第一种情况,php的worker进程池处理慢,无法尽快处理等待accept的链接队列,导致3次握手后的链接队列长时间没有被accept,nginx链接等待超时;返回504后nginx对应的error日志是110: Connection timed out

第二种情况,后端php-fpm执行脚本的时间太长,超过了nginx配置的超时机制,这个时候也是会报出504错误的。

第三种情况,客户端的网络及其差,php将请求处理完交给nginx后,nginx没能在超时时间内将内容全部吐给用户,这时也会超时,只有504而没有502。

减少避免504报错的优化建议

504主要从nginx的配置方考虑,根据业务情况配置好超时的各种机制,包含但不限于下属参数:fastcgi_connect_timeout
fastcgi_send_timeout
fastcgi_read_timeout

另外:在配置过程中,比如遇到大并发或者是特殊业务的场景,不合理的fd、buffer等设置也会带来5XX错误,比如说大并发连接的业务要增大系统和单个程序的fd数量,如果是上传业务要增大头buffer等,这些要视情况而做优化,正所谓道法自然,术变万千,要以不变应万变。 查看全部
    随着php脚本语言使用的普及,目前webserice服务大部分都在用nginx+(php-fpm)的结构,了解了其工作过程后才可以在各个方面想办法做调整优化和故障排查,从以下几点总结一下这种模型。
 

0.png


 
一、nginx和php-fpm的关系和分工
 
nginx是web服务器,php-fpm是一个PHPFastCGI进程管理器,两者遵循fastcgi的协议进行通信,nginx负责静态类似html文件的处理,php-fpm负责php脚本语言的执行,这么设计的目的是为了解耦前端nginx和后端的php,不至于让容易出问题的php脚本堵塞整个nginx的业务处理,影响用户体验,因为php脚本语言的执行是会比较容易出问题的。nginx之所以能处理成千上万高并发业务,除其本身的异步非阻塞模式,在与和其他模块的耦合扩展方法也是分不开的,在nginx的设计里不能接受的就是阻塞,不过并非完全没有梗,比如说用到的最多的多进程单线程的模式,由于nginx日志没有单独的处理进程,如果收集日志时处理不当就会把worker进程堵死。
 
对应nginx+php-fpm的模型结构图如下:

0.jpg

 
1、nginx的工作简介

接到php的脚本请求后,nginx通过fastcgi_pass指令将请求传递给后端php-fpm的worker进程处理,在此过程中,nginx做了各种超时机制、缓存机制、buffer机制和长连接机制等来保障与后端的php-fpm能够良性高效的合作。

在超时机制方面控制nginx对后端php的等待时间,通过各种timeout指令进行控制,例如:
 
fastcgi_connect_timeout :  后端链接时间
fastcgi_send_timeout : 数据发送时间,两次成功发送时间差,不是整个发送时间
fastcgi_read_timeout : 数据接收时间,两次成功接收时间差,不是整个接收时间

当超时后会返回504超时的状态码,在buffer机制指令也有很多,例如:
 
fastcgi_buffer_size 存放fastcgi传过来的响应头,一般设置为分页大小
fastcgi_buffers 存放fastcgi传过来的相应内容,一般设置分页的倍数,格式例如 8 4k|8k
另外还有一些其它的缓存、长连接机制不做介绍,当设置不合理时也会出现5XX错误,nginx的文章介绍写了有很多的,不再做过多的说明。
 
2、php-fpm工作介绍
 
Php-fpm是一个PHPfastcgi进程管理器,在启动后会有master和worker两种进程,master负责接收外部信号和管理worker进程,worker进程是负责干活的,处理nginx传过来的任务。
master进程只有一个,负责监听端口和管理worker进程,每次传来任务,与前端的nginx建立3次握手后放入连接队列,供worker进程进行accept,当worker进程出现错误或执行超时时,负责将worker进程重启或者杀掉,是php-fpm模型中的大内总管。
Worker进程是工作进程,每个worker进程都独立的执行php程序脚本,然后把执行的结果通过fastcgi协议交给nginx,执行过程中受master的管理。在工作中,worker进程去竞争accept管理进程master的链接队列,accept函数将从连接请求队列中获得连接信息,创建新的socket,并返回该套接字的fd,新创建的socket用于服务器与nginx的通信,而原来的套接字仍然处于监听状态。
php-fpm可以配置多个pool,所有pool由master统一管理监听不同端口并分配不同worker进程池,worker进程池支持动态prefork同时也支持静态开启,服务器内存较大时建议直接计算后配置静态资源池,可以减少频繁prefork进程所带来的开销,提高服务质量,由于进程模型越跑程序耗费越大,因为每个worker进程可以配置执行多少个请求后进行重启,对应的池子的指令和执行多少个请求的指令如下:
 
pm = static | dynamic | ondemand :静态池、服务优先、内存优先
pm.max_children = 256 : 开启的最大php进程数
pm.max_requests = 1024 : 在执行了1024个请求后重启worker进程

这也是我们线上服务器的配置,我们线上用的web服务的机器是12核cpu、16G内存,nginx开启12个worker进程,php开启256个进程,跑起来后每个进程大概占用30M内存,也就是(256+12)*30=8G ,另外还跑了一些配管、监控、统计、日志收集等七七八八的软件,整体业务是比较轻松的,这种静态池的配置**减少了prefork进程带来的开销,RT时间100ms以内的占到90%以上(这个与程序写的如何有关),运行一段时间后的开销截图如下:
 
 

0.webp_.jpg

 
二、此模型结构常见的5XX服务器端错误及优化
 
1、nginx日志里产生502错误

第一种情况,php-fpm的worker进程执行php程序脚本时,超过了配置的最长执行时间,master进程将worker进程杀掉,直接返回502。返回502后nginx对应的error日志是104: Connection reset by peer,对应的php执行时间的配置如下,一些版本中php-fpm的配置会覆盖php.ini的配置,使php.ini的配置不起作用:
php.ini中默认30s:max_execution_time =
php-fpm中:request_terminate_timeout =

第二种情况,连接请求数(accpet之前)超出了端口所能监听的tcp连接的最大值(backlog的值),进不了fpm等待accept的链接队列,直接返回502,这里可能会产生tcp重传;返回502后nginx对应的error日志是111: Connection refused, backlog的值是半连接和全连接的总和,他的存在也有短时间缓冲解耦nginx请求与fpm处理的作用,半连接指收到了syn请求,3次握手尚未建立,全连接指的是3次握手已经成功,不过尚未被accpet的请求,fpm里面有调节的参数,如果fpm的参数设置为-1,则默认走的是系统内核参数net.core.somaxconn的设置值,如果不设置可以在/proc/sys/net/core/somaxconn里查看,默认值是128,所以在连接请求较高的业务里要增大这个值。

第三种情况,网络卡时,客户端断开连接,nginx处显示499,然后php检查到前端nginx产生abort后,又master结束此条任务的继而产生502,一般此种情况的报警,先是499,过会儿变成502,再过一会变成504.

减少避免502报错优化建议

502主要从php-fpm的配置方考虑,根据服务器情况,适量增大php-fpm的工作进程数,适当增加php的执行时间,适当增加backlog值。

php的工作进程数也不是越大越好,这种进程模型运行时间长了占的内存会增大,一般一个php进程是占到30M左右的内存,开多少合适自己算吧,nginx的worker进程一般也能跑到30M的内存,综合计算一下;php的执行时间可以根据你的服务标准来设定,超过服务时间浏览器返回的是502错误,这个按照实际的情况处理吧,反正我是觉得执行的慢有返回结果总比直接返回502错误的强;至于backlog值,当程序写的比较好时,建议设置其数量为php工作进程的1到2倍。
 
2、nginx日志里产生504错误

第一种情况,php的worker进程池处理慢,无法尽快处理等待accept的链接队列,导致3次握手后的链接队列长时间没有被accept,nginx链接等待超时;返回504后nginx对应的error日志是110: Connection timed out

第二种情况,后端php-fpm执行脚本的时间太长,超过了nginx配置的超时机制,这个时候也是会报出504错误的。

第三种情况,客户端的网络及其差,php将请求处理完交给nginx后,nginx没能在超时时间内将内容全部吐给用户,这时也会超时,只有504而没有502。

减少避免504报错的优化建议

504主要从nginx的配置方考虑,根据业务情况配置好超时的各种机制,包含但不限于下属参数:
fastcgi_connect_timeout
fastcgi_send_timeout
fastcgi_read_timeout


另外:在配置过程中,比如遇到大并发或者是特殊业务的场景,不合理的fd、buffer等设置也会带来5XX错误,比如说大并发连接的业务要增大系统和单个程序的fd数量,如果是上传业务要增大头buffer等,这些要视情况而做优化,正所谓道法自然,术变万千,要以不变应万变。

Cookie/Session机制是什么样的?

回复

常识zkbhj 回复了问题 • 1 人关注 • 1 个回复 • 2556 次浏览 • 2016-12-19 17:55 • 来自相关话题

PHP函数:array_multisort()

PHPzkbhj 发表了文章 • 0 个评论 • 1158 次浏览 • 2016-12-19 17:25 • 来自相关话题

PHP中array_multisort可以用来一次对多个数组进行排序,或者根据某一维或多维对多维数组进行排序。 
关联(string)键名保持不变,但数字键名会被重新索引,从 0 开始,并以 1 递增。 
输入数组被当成一个表的列并以行来排序——这类似于 SQL 的 ORDER BY 子句的功能。第一个数组是要排序的主要数组。数组中的行(值)比较为相同的话就按照下一个输入数组中相应值的大小来排序,依此类推。——这句话是理解此函数用法的关键。

第一个参数必须是一个数组。接下来的每个参数可以是数组或者是下面列出的排序标志。

排序顺序标志: 
■SORT_ASC - 按照上升顺序排序 
■SORT_DESC - 按照下降顺序排序

排序类型标志: 
■SORT_REGULAR - 将项目按照通常方法比较 
■SORT_NUMERIC - 将项目按照数值比较 
■SORT_STRING - 将项目按照字符串比较

每个数组之后不能指定两个同类的排序标志。每个数组后指定的排序标志仅对该数组有效 - 在此之前为默认值 SORT_ASC 和 SORT_REGULAR。

看看两个实际例子:
1、一次对多个数组进行排序:
$num1 = array(3, 5, 4, 3);
$num2 = array(27, 50, 44, 78);
array_multisort($num1, SORT_ASC, $num2, SORT_DESC);

print_r($num1);
print_r($num2);
//result: Array ( [0] => 3 [1] => 3 [2] => 4 [3] => 5 ) Array ( [0] => 78 [1] => 27 [2] => 44 [3] => 50 )
2、对多维数组(以二位数组为例)进行排序:
$arr = array(
'0' => array(
'num1' => 3,
'num2' => 27
),

'1' => array(
'num1' => 5,
'num2' => 50
),

'2' => array(
'num1' => 4,
'num2' => 44
),

'3' => array(
'num1' => 3,
'num2' => 78
)
);

foreach ( $arr as $key => $row ){
$num1[$key] = $row ['num1'];
$num2[$key] = $row ['num2'];
}

array_multisort($num1, SORT_ASC, $num2, SORT_DESC, $arr);

print_r($arr);
//result:Array([0]=>Array([num1]=>3 [num2]=>78) [1]=>Array([num1]=>3 [num2]=>27) [2]=>Array([num1]=>4 [num2]=>44) [3]=>Array([num1]=>5 [num2]=>50)) 查看全部
PHP中array_multisort可以用来一次对多个数组进行排序,或者根据某一维或多维对多维数组进行排序。 
关联(string)键名保持不变,但数字键名会被重新索引,从 0 开始,并以 1 递增。 
输入数组被当成一个表的列并以行来排序——这类似于 SQL 的 ORDER BY 子句的功能。第一个数组是要排序的主要数组。数组中的行(值)比较为相同的话就按照下一个输入数组中相应值的大小来排序,依此类推。——这句话是理解此函数用法的关键。

第一个参数必须是一个数组。接下来的每个参数可以是数组或者是下面列出的排序标志。

排序顺序标志: 
■SORT_ASC - 按照上升顺序排序 
■SORT_DESC - 按照下降顺序排序

排序类型标志: 
■SORT_REGULAR - 将项目按照通常方法比较 
■SORT_NUMERIC - 将项目按照数值比较 
■SORT_STRING - 将项目按照字符串比较

每个数组之后不能指定两个同类的排序标志。每个数组后指定的排序标志仅对该数组有效 - 在此之前为默认值 SORT_ASC 和 SORT_REGULAR。

看看两个实际例子:
1、一次对多个数组进行排序:
$num1 = array(3, 5, 4, 3);
$num2 = array(27, 50, 44, 78);
array_multisort($num1, SORT_ASC, $num2, SORT_DESC);

print_r($num1);
print_r($num2);
//result: Array ( [0] => 3 [1] => 3 [2] => 4 [3] => 5 ) Array ( [0] => 78 [1] => 27 [2] => 44 [3] => 50 )

2、对多维数组(以二位数组为例)进行排序:
$arr = array(
'0' => array(
'num1' => 3,
'num2' => 27
),

'1' => array(
'num1' => 5,
'num2' => 50
),

'2' => array(
'num1' => 4,
'num2' => 44
),

'3' => array(
'num1' => 3,
'num2' => 78
)
);

foreach ( $arr as $key => $row ){
$num1[$key] = $row ['num1'];
$num2[$key] = $row ['num2'];
}

array_multisort($num1, SORT_ASC, $num2, SORT_DESC, $arr);

print_r($arr);
//result:Array([0]=>Array([num1]=>3 [num2]=>78) [1]=>Array([num1]=>3 [num2]=>27) [2]=>Array([num1]=>4 [num2]=>44) [3]=>Array([num1]=>5 [num2]=>50))

分布式开放消息系统:RocketMQ

工具软件zkbhj 发表了文章 • 0 个评论 • 1419 次浏览 • 2016-12-19 15:05 • 来自相关话题

1、什么是RocketMQ ?RocketMQ 是一款分布式、队列模型的消息中间件,具有以下特点:
能够保证严格的消息顺序提供丰富的消息拉取模式高效的订阅者水平扩展能力实时的消息订阅机制亿级消息堆积能力Metaq3.0 版本改名,产品名称改为RocketMQ
 
下载地址:https://github.com/alibaba/RocketMQ/releases
 
2、分布式消息系统作为实现分布式系统可扩展、可伸缩性的关键组件,需要具有高吞吐量、高可用等特点。而谈到消息系统的设计,就回避不了两个问题:
消息的顺序问题消息的重复问题
   RocketMQ作为阿里开源的一款高性能、高吞吐量的消息中间件,它是怎样来解决这两个问题的?RocketMQ 有哪些关键特性?其实现原理是怎样的?
 
3、关键特性以及其实现原理
 
 
参考文章:http://www.jianshu.com/p/453c6e7ff81c 查看全部
1、什么是RocketMQ ?RocketMQ 是一款分布式、队列模型的消息中间件,具有以下特点:
  • 能够保证严格的消息顺序
  • 提供丰富的消息拉取模式
  • 高效的订阅者水平扩展能力
  • 实时的消息订阅机制
  • 亿级消息堆积能力
  • Metaq3.0 版本改名,产品名称改为RocketMQ

 
下载地址:https://github.com/alibaba/RocketMQ/releases
 
2、分布式消息系统作为实现分布式系统可扩展、可伸缩性的关键组件,需要具有高吞吐量、高可用等特点。而谈到消息系统的设计,就回避不了两个问题:
  • 消息的顺序问题
  • 消息的重复问题

   RocketMQ作为阿里开源的一款高性能、高吞吐量的消息中间件,它是怎样来解决这两个问题的?RocketMQ 有哪些关键特性?其实现原理是怎样的?
 
3、关键特性以及其实现原理
 
 
参考文章:http://www.jianshu.com/p/453c6e7ff81c