[Full-stack] 世上最好语言 - PHP ***

前言


本篇是对个人PHP, Laravel系列博文的总结与思考。

目的在于理清并熟练如下过程:

"需求 --> Usercase --> UI --> 框架 --> 开发"

 

 

 

需求分析 


一、页面初步设计

Ref: [Laravel] 06 - Project: from Usercase to View

1. Pure html 写法

2. 找到其中的公共部分 --> blade模板

3. 布局设计css,bootstrap and jquery

重难点也就是blade,以及bootstra p& jquery。

 

 

二、Common页面模板设计

views -- common -- layouts.blade.php
                -- message.blade.php
                -- validator.blade.php

 

  • Layouts 核心模板

<head>

<title>轻松学会Laravel - @yield('title')</title>

</head>

<body>

Ref: laravel 基础教程 —— Blade 模板引擎【写的不错】

Ref: [Laravel] 04 - Blade templates【关键字的理解】

</body>

 

  • 布局设计

 这部分内容请见:[Full-stack] 网页布局艺术 - Less

 

 

三、路由与MVC框架

  • 有效路由 与 无效路由

无效路由:没有实际页面的路由,且request后,服务器会调用redirect重定向到一个有效路由对应的页面。

Route::group(['middleware' => ['web']], function () {

    Route::get('student/index',       ['uses' => 'StudentController@index' ]);
    Route::any('student/create',      ['uses' => 'StudentController@create']);
    Route::any('student/save',        ['uses' => 'StudentController@save'  ]);
    Route::any('student/update/{id}', ['uses' => 'StudentController@update']);
    Route::any('student/detail/{id}', ['uses' => 'StudentController@detail']);
    Route::any('student/delete/{id}', ['uses' => 'StudentController@delete']);
});

Ref: 路由相关概念:[Laravel] 02 - Route and MVC

 

  • 模型 与 数据库

[1] 首先,pure php 是如何链接数据库的呢?

Goto: [PHP] 07 - Json, XML and MySQL

<?php
$servername = "localhost";
$username   = "username";
$password   = "password";
$dbname     = "myDB";

// 1.创建连接
$conn = new mysqli($servername, $username, $password, $dbname);

// 2.检测连接
if ($conn->connect_error) {
    die("连接失败: " . $conn->connect_error);
} 

// 3.SQL操作
$sql = "INSERT INTO MyGuests (firstname, lastname, email) VALUES ('John', 'Doe', 'john@example.com')"; if ($conn->query($sql) === TRUE) { echo "新记录插入成功"; } else { echo "Error: " . $sql . "<br>" . $conn->error; }
// 4.关闭连接
$conn->close(); ?>

  

[2] Laravel 又是如何通过框架实现的呢?

Goto: [Laravel] 03 - DB facade, Query builder & Eloquent ORM

1. 原始方式

第一步,设置配置文件:[config/database.php]  

第二步,执行sql语句。

use Illuminate\Support\Facades\DB
$students = DB::select('select * from student');

2. 查询构造器

3. Eloquent ORM - 对象关系映射(Object Relational Mapping,简称ORM)

 

  • 路由 --> 控制器 (模型) --> 视图

[1] 路由 到 控制器

Route::any('student/create', ['uses' => 'StudentController@create']);

URL中参数解析:

  (1) router 中获得已定义好的参数。[Laravel] 02 - Route and MVC

  (2) controller 中通过request函数获得URL中key对应的value。[Laravel] 05 - Controller

 

[2] 控制器 with 模型 到 视图

    // 添加页面
    public function create(Request $request)
    {
# 获得模型载体
$student = new Student(); if ($request->isMethod('POST')) { // 控制器验证 or Validator类验证
# 获取数据 $data = $request->input('Student');
# 载体加载了数据,数据库与载体数据同步
if (Student::create($data) ) { return redirect('student/index')->with('success', '添加成功!'); } else { return redirect()->back(); } }
# 视图展示载体
return view('student.create', [ 'student' => $student ]); }

 

 

 

PHP API 设计


一、Pure PHP 封装接口

  • 什么叫封装?

封装一个类,服务器端采用 response 处理以下内容。

code 返回的id,统一编号
message 具体解释,detail
data 具体内容,参数

参数要数组化,构成 $result

$result --> XML or JSON 格式

XML组装时需要一个递归的解析过程: 

public static function xmlToEncode($data) {

  $xml = $attr = "";
  foreach( $data as $key => $value) {

    if (is_numberic($key)) {
      $attr = "id='{$key}'";
      $key  = "item";
        # <item id=[key]> 
    }

    $xml .= "<{$key}><{$attr}>";
    $xml .= is_array($value) ? self::xmlToEncode($value) : $value;
    $xml .= "</{$key}>";  
  }

  return $xml;
}
View Code

 

  • Response 封装

这里可以考虑使用工厂方法。

public static function show($code, $message='', $data=array(), $type=self::JSON) {
    if(!is_numeric($code)) {
        return '';
    }

    $type = isset($_GET['format']) ? $_GET['format'] : self::JSON;

    $result = array(
        'code'    => $code,
        'message' => $message,
        'data'    => $data,
    );
/**
* 以下switch的写法,也可以写成工厂方法的形式,
*/
if($type == 'json') { self::json($code, $message, $data); exit; } elseif($type == 'array') { var_dump($result); } elseif($type == 'xml') { self::xmlEncode($code, $message, $data); exit; } else { // TODO } }

 

 

 二、缓存策略

  • 静态缓存 与 mem缓存

Ref: [Laravel] 11 - WEB API : cache & timer 

此链接内容为下面的缓存三种策略做铺垫。

 

  • 缓冲方案

这里以静态缓冲作为例子,仅考虑后两种方案即可。

Goto: [Laravel] 12 - WEB API : cache implement

 

 

三、数据库链接

需要复习一遍sql语句:[Laravel] 16 - DB: Eloquent

# step 1, 语句编写
$sql
= "select *     from `version_upgrade`     where app_id = " . $appId ."     and status = 1     limit 1";
# step 2,连接
$connect = Db::getInstance()->connect();
#step 3,执行语句
$result = mysql_query($sql, $connect);
#step 4,转化结果格式
mysql_fetch_assoc($result);

 

 

四、版本检查

Ref: [Laravel] 13 - WEB API : update & error tracking 

<?php
require_once('./common.php');

class Init extends Common {
  public function index() {
    $this->check();  # check的实现,判断app的版本是否有问题
/**
* 1.获得手机信息,确认没有问题
* 2.该手机是否需要升级
* implement here.
*/
Response::show(number, '返回给app的一些信息');
  } } -------------------------------------------
$init = new Init(); $init->index();

 

 

五、错误日志 

携带设备信息 device id 的 request 发送到服务器端,

然后,服务器当做 error log 保存起来。

 

 

 

Maravel API 设计


一、前言

  • REST API

Goto: [Node.js] 08 - Web Server and REST API

  • Laravel API

Ref: https://laravel.com/docs/5.6

 

 

二、功能实现

  •  用户注册模块

Goto: [Laravel] 14 - REST API: Laravel from scratch

 

  

三、单元测试

Goto: [Laravel] 15 - REST API: sidebar with unit test

 

 

 

附录


一、PHP 参考手册 

 

二、其他常用函数

  • ucwords() 函数

把每个单词的首字符转换为大写。

$resultClass = ucwords($type);
毕竟url中的参数不能使用大写。
 
  • dirname(__FILE__) 
当前所在目录,也可以是目录所在的目录。
dirname(dirname(__FILE__)); 
假设__FILE__为
/home/web/config/config.php 上面的方法输出为 /home/web

 

  • is_dir()
是目录么 

 

  • file_put_contents()
字符串写入文件
<?php
echo file_put_contents("test.txt","Hello World. Testing!");
?>

 

  • @unlink()
当删除一个不存在或只读的文件时,是要报错的
@ 作用就是:错了也不告诉你!骗你没商量
if(is_null($value)) {
  return @unlink($filename);
}

 

  • is_numeric($var)

常用于检查参数。

if(!is_numeric($appId) || !is_numeric($versionId)) {
  return Response::show(401, '参数不合法');
}

 

  • static:: 

Ref: PHP static关键字的用法及注意点

详见: [PHP] 02 - Namespace & Class

 

 

故事背景


socket.io, node.js, koa为首的一些通信框架和后端技术点。

之后有必要过一遍《NodeJS 设计模式》。

 

 

  

基础概念


一、短轮询、长轮询(comet)、长连接(SSE)、WebSocket

  • 基本概念

Ref: [Node.js] 01 - How to learn node.js

① 短轮询 - 服务器立即响应

② comet 长轮询 - 服务器觉得有必要时(比如发生了变化)才响应

③ SSE - 支持了服务器端的推送

④ WebSocket - 全双工,http的扩展 - Netty, nodejs就是基于此技术的例子

 

  • 最简单的http服务器

使用了“包”,也就是require(<包>),也就谈到了npm, package.json文件。

var http = require('http');

http.createServer( function (request, response) {

    // 发送 HTTP 头部 
    // HTTP 状态值: 200 : OK
    // 内容类型: text/plain
    response.writeHead (200, {'Content-Type': 'text/plain'});

    // 发送响应数据 "Hello World"
    response.end ('Hello World\n');
}).listen(8888);

// 终端打印如下信息
console.log('Server running at http://127.0.0.1:8888/');
超级简单的服务器

 

 

二、单线程模型架构

与Unix环境系统编程的API很像。

Ref: [Node.js] 02 - Read Eval Print Loop

var exec = require('child_process').exec;
var shell = require("shelljs");

/**
* 参数处理模块,变化无穷
*/
var argv = require('yargs').argv;

 

 

三、Buffer 类

Ref: [Node.js] 03 - Buffer, Stream and File IO

一个 Buffer 类似于一个整数数组,但它对应于 V8 堆内存之外的一块原始内存。

一种功能更为全面的Array。

 

 

四、文件系统操作

Ref: Node.js v10.5.0 Documentation

var fs = require("fs"); 

文件读写 默认是异步。

文件流 与事件触发相结合。

const os = require('os');

系统本身的API对接。

 

 

五、事件触发

  • 基本概念

Ref: [Node.js] 04 - Event and Callback

Node.js 的每一个 API 都是异步的

Node.js 基本上所有的事件机制都是用设计模式中观察者模式实现。 

var events       = require('events');
var eventEmitter = new events.EventEmitter();

eventEmitter.on() # 绑定事件
eventEmitter.emit() # 触发事件

参见链接中的:一个综合性的例子

 

  • 事件触发的继承

大多数时候我们不会直接使用 EventEmitter,而是在对象中继承它。

包括 fs、net、 http 在内的,只要是支持事件响应的核心模块都是 EventEmitter 的子类。

举例:老师喊一嗓子,触发每个学生对象喊一句“到”。

 

 

六、模块知识

具体参见:[Node.js] 05 - Modules and Function

var util = require('util'); 

 

 

 

Node 服务器


一、写个服务器

可见,node方式写server之简洁明了。

var http = require('http');

http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('Hello World\n');
}).listen(1337, "127.0.0.1");

console.log('Server running at http://127.0.0.1:1337/');

 

 

 

二、服务器性能

Ref: [Node.js] 06 - Multi-thread and process module

  • 服务器扩展性
    • X轴方向:服务实例拓展
    • y轴方向:功能性的拓展
    • z轴方向:按照业务数据对服务进行拓展(更多的服务分别处理不同的业务)

 

  • Microservices

微服务的容错性 ----> Unity的自治思想

 

  • 对比 Netty

    • 线程数:100;循环次数:100;

    • 线程数:1000;循环次数:10;

    • 线程数:1000;循环次数:100;

 

 

 

Multi-thread/process 实践


Ref: [Node.js] 06 - Multi-thread and process module

JS本身的异步方法,以及node封装的系统接口。

 

/* implement */

 

 

 

 

Server 框架


 

Express 与 Koa 实践,包括涉及到的负载平衡以及相关方案。

如何做massive requests的压力测试?


/* implement */

 

posted @ 2018-07-08 20:05  郝壹贰叁  阅读(322)  评论(0编辑  收藏  举报