十二月
21
2016

笔记019 通过 spl_autoload_register 实现自动加载

spl_autoload_register (PHP 5 >= 5.1.2, PHP 7) spl_autoload_register — 注册给定的函数作为 __autoload 的实现 语法 bool spl_autoload_register ([ callable $autoload_function [, bool $throw = true [, bool $prepend = false ]]] ) 说明 通过这个函数,可以为加载的类指定寻址方式,这样就不用大批量地 require 和 include 了。系统会自动按照指定的规则,到对应的位置下面去寻找需要实例化的类。虽然这个方法比较底层,在有框架的情况下,一般都不需要我们去做这些工作了。但是难免还是有要用的时候,比如我写这个博客的时候,我就自己需要捣腾脚本,这个时候,就绕不开了。下面的例子,就是我的脚本中要用的一个简单的自动加载的程序。 例子 spl_autoload_register(function ($class) { $rootPath = realpath(sprintf('%s/..', __DIR__)); $paths = array( 'src', ); foreach ($paths as $path) { if (is_file( $file = $rootPath . DIRECTORY_SEPARATOR . $path . DIRECTORY_SEPARATOR . $class . '.php' )) { include $file; break; } } }); 注意,匿名函数是 PHP 5.3 及以上 才可以用的,如果发现不能用,检查一下自己的 PHP 版本。我这里只是简单地指定所有的类在我的 src 文件夹下寻找,类名与文件名完全一致。
七月
21
2016

通过反射类实现对类的 protected 和 private 属性及方法的测试

在编写类(Class)的时候,部分方法及属性为了限制访问,会设置为 private 和 protected 权限,尤其是对于类属性来说,为了安全方面的原因,多数是不允许直接访问的。而在测试时,由于无法在外部直接访问,这样的设置会让测试变得很麻烦。当然,所谓的麻烦,也就是在 Hy369 知道 ReflectionObject 相关的类之前的事,因为从麻烦变得简单了,所以 Hy369 的 PHP 博客中便有了这样一篇文章。

阅读全文>>

六月
28
2016

笔记018 PHP中的 constant() 函数

语法 mixed constant ( string $name ) 说明 constant() 函数用于返回一个常量的值。当预先不知道常量的名称,却需要取得该常量的值的时候,该函数特别有用。 通过向 $name 参数传递常量的名称,便可获得对应常量的值。 该函数对于类常量依然适用。 返回值 返回常量的值,若常量未定义,则返回 null,但此时会产生一个 E_WARNING 级别的错误。 示例 <?php define("MAXSIZE", 100); echo MAXSIZE; echo constant("MAXSIZE"); // same thing as the previous line interface bar { const test = 'foobar!'; } class foo { const test = 'foobar!'; } $const = 'test'; var_dump(constant('bar::'. $const)); // string(7) "foobar!" var_dump(constant('foo::'. $const)); // string(7) "foobar!"
三月
24
2016

PHP 正则中的断言

在阅读 symfony 源码的过程中,发现了一个不认识的正则表达式:([^ ]+?)(?: |(?<!\\)"|(?<!\\)'|$),看了很久,还真没有弄懂是要干嘛。 所以赶紧查看了一下 PHP 文档正则表达式的部分,直到翻看到断言这一章的时候,终于算是找到答案了。原来这是运用了 PHP 正则中的断言。 一个断言就是一个对当前匹配位置之前或之后的字符的测试, 它不会实际消耗任何字符。简单的断言代码有\b、\B、 \A、 \Z、\z、 ^、$ 等等。 更加复杂的断言以子组的方式编码。 断言有两种类型: 前瞻断言:用于从当前位置向前测试,注意前瞻表示向当前字符串之后的字符串进行测试。 后瞻断言:用于从当前位置向后测试,注意后瞻表示向当前字符串之前的字符串进行测试。 两种断言又细分为积极断言和消极断言。 前瞻断言中的积极断言以 (?= 开始,用于断言向前测试的结果为真;前瞻断言中的消极断言以 (?! 开始,用于断言向前的测试结果为假。例如: \w+(?=;) 匹配一个单词紧跟着一个分号但是匹配结果不会包含分号 foo(?!bar) 匹配所有后面没有紧跟 ”bar” 的 ”foo” 字符串 但是有个特别需要注意的地方: (?!foo)bar 不能用于测试 bar 前面出现的不是 foo,因为前瞻断言的特性,他只能判断向右的字符串不是 foo,所以在 (?:foo) 遇到 bar 的时候永远为真(我想,此时电脑的心声是:这熊孩子,明明是 bar,还问我是不是 foo,哈哈)。 要实现上例中原本要实现的想法,就得换个法子了,也就是接下来登场的后瞻断言。 后瞻断言中的积极断言以 (?<=开头,消极断言以 (?<! 开头。例如: (?<!foo)bar 用于查找任何前面不是 ”foo” 的 ”bar”。 后瞻断言的内容被严格限制为只能用于匹配定长字符串。但是,如果有多个可选分支, 它们不需要拥有相同的长度。比如 (?<=bullock|donkey) 是允许的, 但是 (?<!dogs?|cats?) 将会引发一个编译期的错误。 多个断言(任意顺序)可以同时出现。 比如 (?<=\d{3})(?<!999)foo 匹配前面有三个数字但不是 ”999” 的字符串 ”foo”。注意, 每个断言独立应用到对目标字符串该点的匹配。 首先它会检查前面的三位都是数字, 然后检查这三位不是 ”999”。 这个模式不能匹配 ”foo” 前面有三位数字然后紧跟 3 位非 999 共 6 个字符的字符串,比如, 它不匹配 ”123abcfoo”。 匹配 ”123abcfoo” 这个字符串的模式可以是 (?<=\d{3}…)(?<!999)foo。 这种情况下,第一个断言查看(当前匹配点)前面的 6 个字符,检查前三个是数字, 然后第二个断言检查(当前匹配点)前三个字符不是 ”999”。 断言可以以任意复杂度嵌套。 比如 (?<=(?<!foo)bar)baz 匹配前面有 ”bar” 但是 ”bar” 前面没有 ”foo” 的 ”baz”。 另外一个模式 (?<=\d{3}…(?<!999))foo 则匹配前面有三个数字字符紧跟 3个不是 999 的任意字符的 ”foo”。 断言子组时非捕获子组,并且不能用量词修饰, 因为对同一件事做多次断言是没有意义的.如果所有的断言都包含一个捕获子组, 那么为了在整个模式中捕获子组计数的目的,它们都会被计算在内。然而, 子字符串的捕获仅可以用于正面断言,因为对于消极的断言是没有意义的。 将断言计算在内,可以拥有的最大子组数量是 200 个。
二月
24
2016

笔记017 PHP中的 session_set_save_handler() 函数

函数说明 session_set_save_handler 函数用于设置用户自定义会话存储。 如果想使用 PHP 内置的会话存储机制之外的方式, 可以使用本函数。 例如,可以自定义会话存储函数来将会话数据存储到数据库。 用法 bool session_set_save_handler ( callable $open , callable $close , callable $read , callable $write , callable $destroy , callable $gc [, callable $create_sid ] ) 从 PHP 5.4 版本开始,可以直接使用更简单的参数进行自定义会话存储设置: bool session_set_save_handler ( SessionHandlerInterface $sessionhandler [, bool $register_shutdown = true ] ) 参数说明 该参数有两种原型: 第一种原型(PHP 5.4+ 版本可用)为: sessionhandler 实现了 SessionHandlerInterface 接口的对象,该对象你可以自定义,也可以使用官方提供的 SessionHandler register_shundown 将函数 session_write_close() 注册为 register_shutdown_function() 函数。 第二种原型为: open(string $savePath, string $sessionName) open 回调函数类似于类的构造函数, 在会话打开的时候会被调用。 这是自动开始会话或者通过调用 session_start() 手动开始会话 之后第一个被调用的回调函数。 此回调函数操作成功返回 true,反之返回 false。 close() close 回调函数类似于类的析构函数。 在 write 回调函数调用之后调用。 当调用 session_write_close() 函数之后,也会调用 close 回调函数。 此回调函数操作成功返回 true,反之返回 false。 read(string $sessionId) 如果会话中有数据,read 回调函数必须返回将会话数据编码(序列化)后的字符串。 如果会话中没有数据,read 回调函数返回空字符串。 在自动开始会话或者通过调用 session_start() 函数手动开始会话之后,PHP 内部调用 read 回调函数来获取会话数据。 在调用 read 之前,PHP 会调用 open 回调函数。 read 回调返回的序列化之后的字符串格式必须与 write 回调函数保存数据时的格式完全一致。 PHP 会自动反序列化返回的字符串并填充 $_SESSION 超级全局变量。 虽然数据看起来和 serialize() 函数很相似, 但是需要提醒的是,它们是不同的。 write(string $sessionId, string $data) 在会话保存数据时会调用 write 回调函数。 此回调函数接收当前会话 ID 以及 $_SESSION 中数据序列化之后的字符串作为参数。 序列化会话数据的过程由 PHP 根据 session.serialize_handler 设定值来完成。 序列化后的数据将和会话 ID 关联在一起进行保存。 当调用 read 回调函数获取数据时,所返回的数据必须要和 传入 write 回调函数的数据完全保持一致。 PHP 会在脚本执行完毕或调用 session_write_close() 函数之后调用此回调函数。 注意,在调用完此回调函数之后,PHP 内部会调用 close 回调函数。 注意: PHP 会在输出流写入完毕并且关闭之后 才调用 write 回调函数, 所以在 write 回调函数中的调试信息不会输出到浏览器中。 如果需要在 write 回调函数中使用调试输出, 建议将调试输出写入到文件。 destroy($sessionId) 当调用 session_destroy() 函数, 或者调用 session_regenerate_id() 函数并且设置 destroy 参数为 true 时, 会调用此回调函数。此回调函数操作成功返回 true,反之返回 false。 gc($lifetime) 为了清理会话中的旧数据,PHP 会不时的调用垃圾收集回调函数。 调用周期由 session.gc_probability 和 session.gc_divisor 参数控制。 传入到此回调函数的 lifetime 参数由 session.gc_maxlifetime 设置。 此回调函数操作成功返回 true,反之返回 false。 create_sid() 当需要新的会话 ID 时被调用的回调函数。 回调函数被调用时无传入参数, 其返回值应该是一个字符串格式的、有效的会话 ID。 返回值 成功时返回 true, 或者在失败时返回 false。 参考链接 官方文档地址
二月
18
2016

symfony 中会涉及到的基本概念

面向对象程序设计(OOP) 这是一个贯彻至 symfony 编程始终的一个概念。 由于 symfony 大量运用了 PHP 5 中的面向对象机制,面向对象程序设计(OOP)是学习 symfony 的先决条件。 当然,一如参考资料所说,这个是个很大的话题,亦不再单独进行记录。 PHP 5 实现了面向对象中的类、对象、方法、继承等。如果你对这些概念不熟悉,建议阅读相关的 PHP 文档,网址如下: 参考网址 魔术方法(Magic Methods) PHP 对象的一个优势是可以使用魔术方法。 这些方法可以不需要修改外部代码而重写一个类的默认行为。魔术方法都是以双下划线(__)开头的。 例如, 当显示一个对象的时候, PHP 会暗中去寻找是否开发者定义过 __toString() 方法: $myObject = new myClass(); echo $myObject; // Will look for a magic method echo $myObject->__toString(); PHP文档参考资料 对象关系映射(ORM) 数据库是关系型数据库。 PHP5 和 symfony 是面向对象的。 为了用面向对象的方法访问数据库, 必须用一个接口来表示对象之间的逻辑关系。 这个接口就叫作对象关系映射(object-relational mapping)或者 ORM。 ORM 是由能够访问数据和存放业务规则的对象组成。 对象/关系抽象层的其中一个优点是可以不用直接去访问数据库。 它会使用经过优化的模型对象来访问当前的数据库。 快速应用程序开发(RAD) 开发网页程序是一件单调乏味的,慢速的事情。按照常规软件开发生存周期(类似于 Rational 统一过程里设想的),要等到有完整的需求, 绘制大量的 UML 图, 产生了大量的正式文档之前准备阶段的文档才能开始开发。 这是由于一般的开发速度,缺少通用性的程序语言(在能正式看到程序可用之前不知道要多 少次的建立,编译,重运行), 最主要的就是客户不会经常改变他们的主意。今天,商业节奏更快了,客户总是倾向于在制作项目中经常改变他们的需求。 当然, 他们期望开发组能接受他们的需求并且快速更改应用程序的架构。幸运的是, 使用脚本语言就像 Perl 和 PHP 会更容易的去实现这些,例如快速应用 程序开发(RAD)和敏捷程序开发。 尽快去建立一个工作原型以便客户可以审阅并且提出问题是一个好方法。 如此周而复始,在较短的开发周期发布新的功能。 有很多东西需要开发者考虑。 开发者不需要去想在未来如何实现一个新功能。 用最简单的方法去实现需要的功能。 这就是 KISS 原则的一个很好体现: Keep It Simple, Stupid。 当需求变化或者功能增加的时候, 有时需要重写代码。 这就叫做重构, 这经常发生在网页应用程序开发中。代码会根据需要改变存放位置。把重复的地方合 并到一个地方,这就是 Don't Repeat Yourself (DRY)原则。 当程序改变后要确保依旧能够运行, 这需要一系列的自动测试来完成。如果写得好的话, 单元测试将是在重构代码后检查的一个好的方法。 一些开发方法学 (development methodologies )甚至于规定在编写代码前先写测试--这就使称之为测试驱动开发(TDD)。 关于敏捷开发还有其它一些原则和好习惯。其中一个最有效率的方法叫做极限编程(Extreme Programming)(简称 XP),极限编程的教材会教你如何去快速而有效的去开发一个程序。 推荐从 Kent Beck(Addison-Wesley)的极限编程系列开始学习。 YAML 来自 YAML 官方网站 的定义: YAML 是一种直观的能够被电脑识别的数据序列化格式,并且它容易被人类阅读,容易与脚本语言交互的。换种说法,YAML 是一种非常简单的类似于 XML 的数据描述语言,语法比 XML 简单很多。 他在描述可以被转化成数组或者 hash 的数据是非常有用,例如: $house = array( 'family' => array( 'name' => 'Doe', 'parents' => array('John', 'Jane'), 'children' => array('Paul', 'Mark', 'Simone') ), 'address' => array( 'number' => 34, 'street' => 'Main Street', 'city' => 'Nowheretown', 'zipcode' => '12345' ) ); 解析这个 YAML 将会自动创建下面的 PHP 数组: house: family: name: Doe parents: - John - Jane children: - Paul - Mark - Simone address: number: 34 street: Main Street city: Nowheretown zipcode: 12345 在 YAML 里面,结构通过缩进来表示,连续的项目通过减号"-"来表示,map 结构里面的键/值(key/value)对用冒号":"来分隔。YAML 也有用来描述好几行相同结构的数据的缩写语法,数组用'[]'包括起来,hash 用'{}'来包括。因此,前面的这个 YAML 可以缩写成这样: house: family: { name: Doe, parents: [John, Jane], children: [Paul, Mark, Simone] } address: { number: 34, street: Main Street, city: Nowheretown, zipcode: 12345 } YAML 是"Yet Another Markup Language(另一种标记语言)"的缩写,读音"yamel",或者"雅梅尔"。这种格式大约是 2001 年出现的,目前为止已经有多 种语言的 YAML 解析器。 YAML 格式的详细规格可以在 YAML 官方网站找到 资料来源 symfony 权威指南
十二月
18
2015

笔记016 PHP中的 get_class() 函数

get_class() 的作用是返回对象的类名。返回 obj 对象对应的类名,如果 obj 不是对象,则会返回 false。通过这个方法,我们在写一些底层相关的代码的时候,可以轻松很多。注意:自 PHP 5 起,如果在对象的方法中调用则 obj 为可选项。

阅读全文>>

十二月
16
2015

笔记015 PHP中?:的特殊用法

从 PHP 5.3 版本开始,三目运算符已经可以将?:连在一起使用了,这是一个相当有用的改变,可以帮我们精简代码,使整个代码更加便于阅读。所以Hy369迫不及待地将其写入了自己的PHP博客中,赞一个。

阅读全文>>

十一月
05
2015

笔记014 PHP正则表达式的分隔符

写在前面 Hy369平时使用的 PHP 正则分隔符是斜杠(/,forward slash)。甚至于一度以为PHP的正则分隔符就只有这个。 嘿嘿,直到今日,看到一个颇为奇怪的以 # 号作为正则分隔符的例子。看到这个”奇怪“的正则表达式,我忍不住找度娘问了一下。结果就是:我愣住了。 真的,直到这一刻,我才直到,PHP下的正则分隔符,其实并非只能是 / 的。 好了,接下来记录一下这个让 Hy369 颇为惊喜的知识点吧。 PHP 正则表达式的分隔符 PHP中,正则表达式的分隔符,可以是除了:字母、数字、反斜杠、空白字符 以外的任何字符。 经常使用的分隔符有:斜杠(/,forward slash),井号(#,hash sign)和波浪号(~,tilde)。 也就是说,可以是下面这些模式: /test string/ #^[^0-9]Hy369$# +php blog+ %[A-Za-z0-9_-]% 要点说明 如果在某个模式中,正则表达式中需要使用到这个模式中的分隔符,则需要在这个分隔符前面添加反斜杠。例如: /http:\/\// 在这种情况下,整个正则表达式显得不是很直观。这个时候,就可以考虑换一个分隔符,用以增强正则表达式的可读性了。因此,上面的正则表达式可以替换为这样: #http://#
十月
10
2015

笔记012 PHP中的list语言结构

PHP中有一种和函数用法很相似的东西,叫做语法结构。因为这种特性,一般将其归于函数中进行介绍。目前Hy369接触到的语法结构有:echo,print,array。当然此次提到的list也是一种语法结构。 至于还有没有其他的语法结构,Hy369也没有特别去深究这个,所以不甚清楚,以后注意到再说吧。 list的作用是用数组为一组变量赋值。其语法为: list(var1,var2...) 通过list可以很方便地将数组中的值赋予指定的变量。这里给出两个例子: <?php $a=array("a"=>"Dog","b"=>"Cat","c"=>"Horse"); print_r($a); 输出结果为: Array ( [a] => Dog [b] => Cat [c] => Horse ) <?php $my_array = array("Dog","Cat","Horse"); list($a, , $c) = $my_array; echo "Here I only use the $a and $c variables."; Here I only use the Dog and Horse variables. 仔细注意一下第二个例子。Hy369以前就为了获得非第一个数组的值,写过类似list($a,$b,$c) = $array的代码,然后输出我仅仅需要的$c的值。当时还不知道可以直接写成list(,,$c)=$arra就可以了(注意逗号)。现在想来,还是略微有些汗颜啊。