PHP M3U8 2.0 发布,以及我为什么要做这些修改

在 2015 年因公司要涉及视频相关业务,我开始和 m3u8 格式接下了『梁子』,到 2016 年 2 月底,我开源了能读写 m3u8 文件格式的核心代码,也就是现在的 PHP M3U8,本来只是抱着把自己的知识保存一份在网上这个想法才做开源这件事情,没想到还真的有人使用这个库,并且后来陆续对更多的 m3u8 格式的标签做了支持。目前我在公司已经不负责视频相关的业务,但这个项目就像有生命一样并没有停止成长,从 1.0.0 到 1.6.0,这让我感到欣慰,也让我觉得有责任把此项目做得更好。

一年多过去了,我最近一段时间一直再思考,PHP M3U8 到底应该是什么,慢慢得我的想法越来越明确:它应该就是一个很单纯的项目,单纯得只做但是一定要做好一件事情,就是解析/生成 M3u8 格式的内容。

在 1.6 版本,m3u8 可以通过 loader 从文件,或者通过网络去读取 M3U8 文件,甚至还能让 load 注入 cache 模块,将网络内容进行缓存。听起来其实也很美好不是吗?但对于一个开源软项目来说,我认为此功能放在 PHP M3U8 项目里有点不合适了,这不仅是对此项目『使命』的纯粹性的追求,纯粹性的追求其实就是各自干好各自的事。目前对于网络资源访问来说,已经有 Guzzle 这样很优秀的项目了,而缓存功能也有很多基于 PSR-6开源项目你随便选。Guzzle 的新版本里去掉了直接将读取的 JSON 内容解析成 PHP 数组的功能,也应该是基于此想法。

2017-11-13 补充:有网友跟我反应,干嘛把缓存去掉啊多么好用的功能……哭笑不得哭笑不得……我只能跟大家说抱歉为了代码上的小洁癖,我只能帮大家到生成/解析 M3U8 这儿了……而且话说回来,能用自己喜欢的缓存库管理缓存,那不是更美好吗。

除了删除一些可以脱离于 PHP M3U8 的功能,2.0 最重大的改动是添加 DumpableInterface。1.6 项目看上去一切似乎都很好,Parser 专门用来解析,Dumper 专门用来生成 M3U8 内容,而 M3u8 类 就是一个单纯的容器。但随着对 M3u8 更多标签得支持,ParserDumper 的代码越来越多,特别是 lex 方法,充满了类似下面的代码:

从长期发展来看,这不是一个好现象,你不能指望着这个方法能把所有的 M3U8 的内容都解析,否则随着对越来越多标签得支持,这个类就会变成一个庞然大物,维护性变得越来越差。要解决这个问题,我的思路是利用 DumpableInterface,将解析和生成 M3u8 的能力和责任,从 ParserDumper 中分出去,委托给实现 DumpableInterface 的 Tag 类、容器类或者集合类。如果你知道 Composite 设计模式,应该会有一种熟悉的感觉:

首先 M3u8 本身实现此接口,让其拥有读和生成 m3u8 内容的能力:

当然,实际 2.0 发布时,M3u8 类并不是直接实现 DumpableInterface 接口,而是继承了一个抽象的容器类,但这并不影响思路。可以看到 M3u8 实际并没有亲自去读取或者生成 M3U8 内容,它是把工作委托给了同样实现 DumpableInterface 接口的其他类实现的,其中包含标签类,比如 Tag\TargetDurationTag,才是实际真正读取和生成内容的类

注:AbstractHeadTag 实现了 DumpableInterface

还有一些类跟 M3u8 类类似,并不是真正读取和生成 M3U8 的,而只是个容器,比如 Segment 类,关键代码与 M3u8 类似,我就不一一列举了。

总之改造之后,如果要对新的标签进行支持,就不是直接增加某个方法的代码,而是通过增加类来实现,很好遵守了面向对象的『开放封闭原则』,实现更好的维护性。

接下来是性能的问题。我之前写了一篇文章,提到如果只是判断一个字符串是否是某个字符串开头,使用 strpos 函数比 preg_match 速度快了不止一星半点儿。事实上,Symfony 在最近的版本里,对路由系统做的优化,也是将以前直接通过正则判断路由规则是否匹配,改成先判断 URL 是否是路由规则里的某固定部分字符串开头,如果是,再通过正则判断路由是否匹配,以及通过正则找到 URL 里的参数信息。

最后,欢迎大家 Pull Request,让 PHP M3U8 能支持更多的标签。

wx pay

CC BY-NC-ND 4.0 PHP M3U8 2.0 发布,以及我为什么要做这些修改 by Chrisyue's Blog is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.

发表评论

电子邮件地址不会被公开。

ten × one =