分类目录归档:PHP

PHP源码,PHP扩展,PHP程序

50天1个亿,不曾到过的世界-创业半年小结

 

2015年过完年,er又打来了电话,从去年开始,已经是第6次了,包包已经会走了,开始学会通过撒娇、大哭达到自己的目的。和er聊了1个小时,答应晚上和夫人商量一下,心已动摇。这个问题和夫人已讨论多次,还是在犹豫,不知是对未知的恐惧,还是对当下的不舍。

最终决定去上海,和er一起创业。梦想还是要有的,万一实现了呢。

选择离开

”橘子红了,是该摘了。“ -- 《橘子红了》

在腾讯的生活充实,有序,领导重视,同事nice,一切的一切都显示得让人无法离开。

创业是选择要未来,而不是现在--冯仑。

这样的当下,这样的现在,真的舍得?

和leader面谈、和总监面谈、和HR面谈、和GM面谈,惭愧,愧疚,不舍……

一切显示如此匆忙,在腾讯的日子越来越少,看着周围的同事都在忙活,心里不免有一些失落……

离别总是别样的风景,在腾讯的682天,2次晋升、3次发文奖励、1次优秀员工,得到了自己想得到的,遇见了自己该遇见的。在腾大7楼退掉工卡,慢慢走出腾讯大楼,回头看去,有些模糊了。

重新启程

”天青色等烟雨,而我在等你。“——《青花瓷》

3.31号,愚人节的前一天,从上海浦东机场转磁悬浮,5站地铁,到了世纪大道,在2号口见到了依稀有些丰满的er,在网上认识很多年,一直未曾见过面,总算见到活的张er。第一次见面,仿佛现实中认识了很多年,是如此熟悉。

到了办公室,略拥挤,er说已经在张罗新的办公场地了,先将就下,研发部20多人,移动开发,后台、前端、设计、测试。已经是下班时间了,还有一半的人在,有新版本准备上线。

之前已经了解过后端的代码了,对于数据库结构及代码基本已经摸清了,后面就是人员的磨合,对具体业务和流程的熟悉,紧张而忙碌。

一晃一月过去了,经历了几次问题,幸运的是最终都得以妥善解决。在此期间日志系统、监控系统、数据监控系统等周边系统逐步上线,一切朝着稳定的方向前进。

新的挑战

”谁的江山,马蹄声狂乱,我一身的戎装,呼啸沧桑“——《菊花台》

搬到新的办公场地,还没有装修好,一切从简。

面对着黄浦江,看着江上船来船往。

有一天,er忽然抬头笑道:你看,这江边有很多树啊

我道:嗯。 

er道:你可知道有多少棵 

我道:三十七棵。 

er的心沉落了下去,笑容也冻结。 

因为他数过江边的树。他了解一个人在数树时,那是多么寂寞。

4月25日,火理财项目正式启动,第4天后台所有接口ready,第8天,iOS版本出企业版,第10天,安卓版上线,创业的速度,创业的激情,狼性的团队,已不再是寂寞。

内测版通过,公测版通过,5月正式上线。

不曾到过的世界

“有的人求名,有的人求利,我求的是什么呢?”  -——《陆小凤传奇》

第1期,1万

第2期,50万 144小时

第3期,100万 14小时

第4期,100万 10小时

……

……

第65期,700万 12小时

到第40期,项目投资总额就已经超过了1个亿。

见或不见,一个亿就在那里,不悲不喜

念或不念,一天700万就在那里,只增不减

跟或不跟,各种问题就在那里,不增只减

这样的一个世界,光怪陆离,不曾到过,曾想过,只是没想过会来得这么快。

手机24小时开机,电脑24小时在身边,快速处理所有发生的问题,我们做的是金融,过手的都是钱,不能有个万一,兢兢业业,诚惶诚恐。

新版快速迭代,两周一个版本,每天后端都有迭代发布,新的规划正在实现,如此滚动……

后记一 关于技术

  • 当业务需要时,使用数据库的最高级别的事务机制保证数据的完整性;
  • 在数据库层面制定好数据约束,即使代码出错最终也不会影响数据;
  • 用户的操作最好在数据中体现出来,确保数据的完整性,关键性操作数据需要有日志类结构存在
  • 如果有第三方接口、服务或数据,在离这些接口、服务最近的地方我们需要有一个完整的日志,忠实于数据的出和入。
  • 初期个人分支开发,主干发布,中后期版本分支开发,主干发布,确保主干的持续可用。
  • 如果可以用人肉临时去解决,而技术要花比较大的成本或难度,那么直接用人去解决吧。
  • 在做方案时需要考虑数据的可追溯,特别是重要数据,简单一点留个操作日志,复杂一些,从数据结构上保证数据的可追溯。

后记二 关于管理

  • 不认同,但是执行
  • 我们要依次管理好人、产品(包括技术)和利润
  • 项目管理方式得看人,员工能力不足管理跟上,员工能力足够可以粗放管理
  • 打工要nice,创业要狼性,一团和气,必然低效
  • 当团队成员能力不齐,有高有低时,需要采用不同的管理方式,对于水平高的要多放手,少跟进,关注结果,对于水平不高的,要排期到天,多跟进。
  • 创业时需要考虑人力成本,以及人的投入产生比,重要的人做重要的事情,让其发挥其应有的价值,不合适的人要早点淘汰。
  • 管理者的分工是让大家更好,更流畅的协同工作,向同一个目标前进。团队成员可以个性鲜明,但是不能让大多数人迁就极个别的人。
  • 上层看问题,下层做事情
  • 管理者的工作:收集信息,决策

最后 招聘

开发经理

我们希望你是:

  • 能cover住20人+的团队的能力,不仅仅是某种技术
  • 能cover住每天上千万的资金流
  • 能够把握住项目的节奏,对项目结果负责

除了开发经理,我们还需要更多的PHP、安卓、iOS、前端、UI、Java、测试。欢迎推荐和自荐,base in 上海。

我的QQ:81894135

PHP的压缩函数实现:gzencode、gzdeflate和gzcompress

  • gzencode 默认使用ZLIB_ENCODING_GZIP编码,使用gzip压缩格式,实际上是使用defalte 算法压缩数据,然后加上文件头和adler32校验
  • gzdeflate 默认使用ZLIB_ENCODING_RAW编码方式,使用deflate数据压缩算法,实际上是先用 LZ77 压缩,然后用霍夫曼编码压缩
  • gzcompress ;默认使用ZLIB_ENCODING_DEFLATE编码,使用zlib压缩格式,实际上是用 deflate 压缩数据,然后加上 zlib 头和 CRC 校验
  • 这三个函数的比较实质上是三种压缩方法:deflate, zlib, gzip的比较。
    从性能的维度看:deflate 好于 gzip 好于 zlib
    从文本文件默认压缩率压缩后体积的维度看:deflate 好于 zlib 好于 gzip

    这三种算法中gzip 、zlib的作者都是Jean-Loup Gailly和 Mark Adler。
    这两种算法以及图形格式png,使用的压缩算法却都是deflate算法。
    deflate算法是同时使用了LZ77算法与哈夫曼编码(Huffman Coding)的一个无损数据压缩算法。
    它最初是由Phil Katz为他的PKZIP归档工具第二版所定义的,后来定义在 RFC 1951规范中。

    deflate算法的压缩与解压的实现过程可以在压缩库zlib上找到。
    PHP的压缩实现依赖于zlib,zlib是一个提供了 deflate, zlib, gzip 压缩方法的函数库。
    我们所使用的上面三个函数,将参数中的encoding转为相同,压缩率设置相同,则其最终调用的是同一个函数,效果和性能一样。

    PHP的zlib实现是以扩展的方式存在于ext/zlib目录中。通过deflateInit2() + deflate() + deflateEnd()三个函数配合完成压缩功能,inflateInit2() + inflate() + inflateEnd()三个函数配合完成解压功能。压缩最终都是通过php_zlib_encode函数实现调用,除了输入的字符串,压缩率,结果的输出外,不同的入口函数调用参数不同的是其encoding。deflateInit2的第四个参数指定encoding,PHP定义了三个常量:

     #define PHP_ZLIB_ENCODING_RAW          -0xf      //deflate -15
    #define PHP_ZLIB_ENCODING_GZIP          0x1f      //gzip 15 + 16
    #define PHP_ZLIB_ENCODING_DEFLATE     0x0f      // zlib 15

    三个函数在调用过程可以直接指定encoding使用其它的算法:

    zlib:   ZLIB_ENCODING_DEFLATE 
    gzip: ZLIB_ENCODING_GZIP
    deflate: ZLIB_ENCODING_RAW

    此三个函数是三种算法的简单调用方式,以更好的命名展现。三个函数间可以通过指定相同的encoding达到相同的效果,并且PHP也提供zlib_encode函数作为通用的压缩函数。

    参考资料:

    http://www.gzip.org/zlib/rfc-deflate.html

PHP成员变量获取对比

有如下4个代码示例,你认为他们创建对象,并获得成员变量的速度排序是怎样的?

1:将成员变量设置为public,通过赋值操作给成员变量赋值,直接获取变量

	class Foo {
		public $id;
	}
 
	$data = new Foo;
	$data->id = 10;
	echo $data->id;

2:将成员变量设置为public,通过构造函数设置成员变量的值,直接获取变量

        class Foo2 {
		public $id;
		public function __construct($id) {
			$this->id = $id;
		}
	}
 
	$data = new Foo2(10);
	echo $data->id;

3:将成员变量设置为protected,通过构造函数设置成员变量的值,通过成员方法获取变量

 
     class Foo3 {
		protected $id;
		public function __construct($id) {
			$this->id = $id;
		}
 
		public function getId() {
			return $this->id;
		}
	}
	$data = new Foo3(10);
	echo $data->getId();

4:将成员变量设置为protected,通过构造函数设置成员变量的值,通过魔术方法获取变量

 
     class Foo4 {
		protected $id;
		public function __construct($id) {
			$this->id = $id;
		}
 
		public function __get($key) {
			return $this->id;
		}
	}
	$data = new Foo4(10);
	echo $data->id;

按执行速度快慢排序: 1243
咱们先看其opcode:

1:

   	1  ZEND_FETCH_CLASS	4 	:4 	'Foo'
	2  NEW      			$5	:4
	3  DO_FCALL_BY_NAME			0          
	4  ASSIGN     				!0, $5
	5  ZEND_ASSIGN_OBJ			!0, 'id'
	6  ZEND_OP_DATA				10
	7  FETCH_OBJ_R			$9	!0, 'id'
	8  ECHO        				$9

2:

	1  ZEND_FETCH_CLASS	4 	:10	'Foo2'
	2  NEW             		$11	:10
	3  SEND_VAL        			10
	4  DO_FCALL_BY_NAME		1 
	5  ASSIGN    				!1, $11
	6  FETCH_OBJ_R			$14	!1, 'id'
	7  ECHO        				$14

3:

	1  ZEND_FETCH_CLASS	4 	:15	'Foo3'
	2  NEW         			$16	:15
	3  SEND_VAL     			10
	4  DO_FCALL_BY_NAME			1          
	5  ASSIGN  	   			!2, $16
	6  ZEND_INIT_METHOD_CALL	!2, 'getId'
	7  DO_FCALL_BY_NAME		0 	$20     
	8  ECHO       				$20

4:

	1  ZEND_FETCH_CLASS	4  :21	'Foo4'
	2  NEW          		$22	:21
	3  END_VAL      			10
	4  DO_FCALL_BY_NAME		1          
	5  ASSIGN        			!3, $22
	6  FETCH_OBJ_R  		$25 !3, 'id'
	7   ECHO  				$25

根据上面的opcode,参照其在zend_vm_execute.h文件对应的opcode实现,我们可以发现什么?

一、PHP内核创建对象的过程分为三步:

  1. ZEND_FETCH_CLASS 根据类名获取存储类的变量,其实现为一个hashtalbe EG(class_table) 的查找操作
  2. NEW 初始化对象,将EX(call)->fbc指向构造函数指针。
  3. 调用构造函数,其调用和其它的函数调用是一样,都是调用zend_do_fcall_common_helper_SPEC

二、魔术方法的调用是通过条件触发的,并不是直接调用,如我们示例中的成员变量id的获取(zend_std_read_property),其步骤为:

  1. 获取对象的属性,如果存在,转第二步;如果没有相关属性,转第三步
  2. 从对象的properties查找是否存在与名称对应的属性存在,如果存在返回结果,如果不存在,转第三步
  3. 如果存在__get魔术方法,则调用此方法获取变量,如果不存在,报错

回到排序的问题:

一、第一个和第二个的区别是什么?

第二个的opcode比第一个要少,反而比第一个要慢一些,因为构造函数多了参数,多了一个参数处理的opcode。参数处理是一个比较费时的操作,当我们在做代码优化时,一些不必要的参数能去掉就去掉;当一个函数有多个参数时,可以考虑通过一个数组将其封装后传递进来。

二、为啥第三个最慢?

因为其获取参数其本质上是一次对象成员方法的调用,方法的调用成本高于变量的获取

三、为啥第四个比第三个要快?

因为第四个的操作实质上获取变量,只不过其内部实现了魔术方法的调用,相对于用户定义的方法,内部函数的调用的效率会高。因此,当我们有一些PHP内核实现的方法可以调用时就不要重复发明轮子了。

四、为啥第四个比第二个要慢?

因为在PHP的对象获取变量的过程中,当成员变量在类的定义不在在时,会去调用PHP特有的魔术方法__get,多了一次魔术方法的调用。

总结一下:

  1. 使用PHP内置函数
  2. 并不是事必面向对象(OOP),面向对象往往开销很大,每个方法和对象调用都会消耗很多内存。
  3. 尽量少用魔术方法 — 除非有必要,不要用框架,因为框架都有大量的魔术方法使用。
  4. 在性能优先的应用场景中,将成员变量设置为public,不失为一种比较好的方法,当你需要用到OOP时。
  5. 能使用PHP语法结构的不要用函数,能使用内置函数的不要自己写,能用函数的不要用对象