作者简介:

       姜海强:闷骚码农,互联网行业摸爬滚打数余载,先后担任中国体育直播TV主程、网信集团先锋支付架构师、奇虎360服务器端资深开发。热爱技术,喜欢分享,热衷领域:PHP/Golang语言、面向对象设计模式、Redis、Yaf、Yii2、微服务等。

视频课程

yaf+yar微服务-腾讯课堂
yaf+yar微服务-51CTO学院
CSDN学院

Github

个人主页
swoole-boot
roach
roach-orm

QQ群:

姜海强的QQ群

公众号:

360tryst公众号

模板模式

模板模式准备一个抽象类,将部分逻辑以具体方法以及具体构造形式实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑。不同的子类可以以不同的方式实现这些抽象方法,从而对剩余的逻辑有不同的实现。先制定一个顶级逻辑框架,而将逻辑的细节留给具体的子类去实现。

讲到模板模式,我不得不提的就是我们著名的PSR-3规范,PSR-3为我们提供了模板的接口

  1. <?php
  2. namespace Psr\Log;
  3. /**
  4. * Describes a logger instance.
  5. *
  6. * The message MUST be a string or object implementing __toString().
  7. *
  8. * The message MAY contain placeholders in the form: {foo} where foo
  9. * will be replaced by the context data in key "foo".
  10. *
  11. * The context array can contain arbitrary data, the only assumption that
  12. * can be made by implementors is that if an Exception instance is given
  13. * to produce a stack trace, it MUST be in a key named "exception".
  14. *
  15. * See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md
  16. * for the full interface specification.
  17. */
  18. interface LoggerInterface
  19. {
  20. /**
  21. * System is unusable.
  22. *
  23. * @param string $message
  24. * @param array $context
  25. * @return void
  26. */
  27. public function emergency($message, array $context = array());
  28. /**
  29. * Action must be taken immediately.
  30. *
  31. * Example: Entire website down, database unavailable, etc. This should
  32. * trigger the SMS alerts and wake you up.
  33. *
  34. * @param string $message
  35. * @param array $context
  36. * @return void
  37. */
  38. public function alert($message, array $context = array());
  39. /**
  40. * Critical conditions.
  41. *
  42. * Example: Application component unavailable, unexpected exception.
  43. *
  44. * @param string $message
  45. * @param array $context
  46. * @return void
  47. */
  48. public function critical($message, array $context = array());
  49. /**
  50. * Runtime errors that do not require immediate action but should typically
  51. * be logged and monitored.
  52. *
  53. * @param string $message
  54. * @param array $context
  55. * @return void
  56. */
  57. public function error($message, array $context = array());
  58. /**
  59. * Exceptional occurrences that are not errors.
  60. *
  61. * Example: Use of deprecated APIs, poor use of an API, undesirable things
  62. * that are not necessarily wrong.
  63. *
  64. * @param string $message
  65. * @param array $context
  66. * @return void
  67. */
  68. public function warning($message, array $context = array());
  69. /**
  70. * Normal but significant events.
  71. *
  72. * @param string $message
  73. * @param array $context
  74. * @return void
  75. */
  76. public function notice($message, array $context = array());
  77. /**
  78. * Interesting events.
  79. *
  80. * Example: User logs in, SQL logs.
  81. *
  82. * @param string $message
  83. * @param array $context
  84. * @return void
  85. */
  86. public function info($message, array $context = array());
  87. /**
  88. * Detailed debug information.
  89. *
  90. * @param string $message
  91. * @param array $context
  92. * @return void
  93. */
  94. public function debug($message, array $context = array());
  95. /**
  96. * Logs with an arbitrary level.
  97. *
  98. * @param mixed $level
  99. * @param string $message
  100. * @param array $context
  101. * @return void
  102. */
  103. public function log($level, $message, array $context = array());
  104. }

以上代码提供了记录各个级别日志的接口,下面我们使用模板模式做一个日志的实现。

  1. <?php
  2. /**
  3. * Describes log levels.
  4. */
  5. class LogLevel
  6. {
  7. const EMERGENCY = 'emergency';
  8. const ALERT = 'alert';
  9. const CRITICAL = 'critical';
  10. const ERROR = 'error';
  11. const WARNING = 'warning';
  12. const NOTICE = 'notice';
  13. const INFO = 'info';
  14. const DEBUG = 'debug';
  15. }
  16. /**
  17. * Class ILogger
  18. * @datetime 2020/7/17 7:16 PM
  19. * @author roach
  20. * @email jhq0113@163.com
  21. */
  22. abstract class ILogger
  23. {
  24. /**
  25. * @param string $message
  26. * @param array $context
  27. * @return string
  28. * @datetime 2020/7/17 7:17 PM
  29. * @author roach
  30. * @email jhq0113@163.com
  31. */
  32. public static function interpolate($message, array $context = array())
  33. {
  34. // build a replacement array with braces around the context keys
  35. $replace = array();
  36. foreach ($context as $key => $val) {
  37. // check that the value can be cast to string
  38. if (!is_array($val) && (!is_object($val) || method_exists($val, '__toString'))) {
  39. $replace['{' . $key . '}'] = $val;
  40. }
  41. }
  42. // interpolate replacement values into the message and return
  43. return strtr($message, $replace);
  44. }
  45. /**
  46. * System is unusable.
  47. *
  48. * @param string $message
  49. * @param array $context
  50. * @return void
  51. */
  52. public function emergency($message, array $context = array())
  53. {
  54. $this->log(LogLevel::EMERGENCY, $message, $context);
  55. }
  56. /**
  57. * Action must be taken immediately.
  58. *
  59. * Example: Entire website down, database unavailable, etc. This should
  60. * trigger the SMS alerts and wake you up.
  61. *
  62. * @param string $message
  63. * @param array $context
  64. * @return void
  65. */
  66. public function alert($message, array $context = array())
  67. {
  68. $this->log(LogLevel::ALERT, $message, $context);
  69. }
  70. /**
  71. * Critical conditions.
  72. *
  73. * Example: Application component unavailable, unexpected exception.
  74. *
  75. * @param string $message
  76. * @param array $context
  77. * @return void
  78. */
  79. public function critical($message, array $context = array())
  80. {
  81. $this->log(LogLevel::CRITICAL, $message, $context);
  82. }
  83. /**
  84. * Runtime errors that do not require immediate action but should typically
  85. * be logged and monitored.
  86. *
  87. * @param string $message
  88. * @param array $context
  89. * @return void
  90. */
  91. public function error($message, array $context = array())
  92. {
  93. $this->log(LogLevel::ERROR, $message, $context);
  94. }
  95. /**
  96. * Exceptional occurrences that are not errors.
  97. *
  98. * Example: Use of deprecated APIs, poor use of an API, undesirable things
  99. * that are not necessarily wrong.
  100. *
  101. * @param string $message
  102. * @param array $context
  103. * @return void
  104. */
  105. public function warning($message, array $context = array())
  106. {
  107. $this->log(LogLevel::WARNING, $message, $context);
  108. }
  109. /**
  110. * Normal but significant events.
  111. *
  112. * @param string $message
  113. * @param array $context
  114. * @return void
  115. */
  116. public function notice($message, array $context = array())
  117. {
  118. $this->log(LogLevel::NOTICE, $message, $context);
  119. }
  120. /**
  121. * Interesting events.
  122. *
  123. * Example: User logs in, SQL logs.
  124. *
  125. * @param string $message
  126. * @param array $context
  127. * @return void
  128. */
  129. public function info($message, array $context = array())
  130. {
  131. $this->log(LogLevel::INFO, $message, $context);
  132. }
  133. /**
  134. * Detailed debug information.
  135. *
  136. * @param string $message
  137. * @param array $context
  138. * @return void
  139. */
  140. public function debug($message, array $context = array())
  141. {
  142. $this->log(LogLevel::DEBUG, $message, $context);
  143. }
  144. /**
  145. * Logs with an arbitrary level.
  146. *
  147. * @param mixed $level
  148. * @param string $message
  149. * @param array $context
  150. * @return void
  151. */
  152. abstract public function log($level, $message, array $context = array());
  153. }
  154. /**
  155. * Class File
  156. * @datetime 2020/7/17 7:23 PM
  157. * @author roach
  158. * @email jhq0113@163.com
  159. */
  160. class File extends ILogger
  161. {
  162. /**
  163. * @var string
  164. * @datetime 2020/7/17 7:20 PM
  165. * @author roach
  166. * @email jhq0113@163.com
  167. */
  168. protected $_fileName;
  169. /**
  170. * @param $fileName
  171. * @datetime 2020/7/17 7:21 PM
  172. * @author roach
  173. * @email jhq0113@163.com
  174. */
  175. public function setFileName($fileName)
  176. {
  177. $this->_fileName = $fileName;
  178. }
  179. /**
  180. * @param string $level
  181. * @param string $message
  182. * @param array $context
  183. * @datetime 2020/7/17 7:23 PM
  184. * @author roach
  185. * @email jhq0113@163.com
  186. */
  187. public function log($level, $message, array $context = array())
  188. {
  189. $message = '{datetime} {level} {ip} {url} '.$message.PHP_EOL;
  190. $context['datetime'] = date('Y-m-d H:i:s');
  191. $context['level'] = $level;
  192. $context['ip'] = $_SERVER['REMOTE_ADDR'];
  193. $context['url'] = $_SERVER['REQUEST_URI'];
  194. $message = self::interpolate($message, $context);
  195. file_put_contents($this->_fileName, $message, FILE_APPEND | LOCK_EX);
  196. }
  197. }
  198. class Db extends ILogger
  199. {
  200. /**
  201. * @var \PDO
  202. * @datetime 2020/7/17 7:24 PM
  203. * @author roach
  204. * @email jhq0113@163.com
  205. */
  206. protected $_pdo;
  207. /**
  208. * @param PDO $pdo
  209. * @datetime 2020/7/17 7:24 PM
  210. * @author roach
  211. * @email jhq0113@163.com
  212. */
  213. public function setPdo(\PDO $pdo)
  214. {
  215. $this->_pdo = $pdo;
  216. }
  217. /**
  218. * @param mixed $level
  219. * @param string $message
  220. * @param array $context
  221. * @datetime 2020/7/17 7:28 PM
  222. * @author roach
  223. * @email jhq0113@163.com
  224. */
  225. public function log($level, $message, array $context = array())
  226. {
  227. $message = self::interpolate($message, $context);
  228. $stmt = $this->_pdo->prepare('INSERT INTO `roach_log`(`level`,`ip`,`url`,`msg`,`add_time`)VALUES(?,?,?,?,?)');
  229. $stmt->execute([
  230. $level,
  231. $_SERVER['REMOTE_ADDR'],
  232. $_SERVER['REQUEST_URI'],
  233. self::interpolate($message, $context),
  234. time()
  235. ]);
  236. }
  237. }

分析以上代码,ILogger是抽象的模板类,实现了部分逻辑,但是log方法没有实现,交给子类实现,作者实现了FileDb子类,如果您感兴趣可以实现其他类,如RedisKafka等。

看过策略模式文章的同学也许有疑问了,这不是策略模式吗?把log方法封装了起来,从本质上来讲算是解决了不同算法的问题,但是严格上来讲,缺少了一个Context对象,不过不重要,只要我们的代码符合开闭原则,我们以设计模式六大原则来编写代码就可以了,严格按照模式来编写代码是没有意义的。

QQ群:

姜海强的QQ群

公众号:

360tryst公众号