Restful的实例

Restful的实例
Apache路由重写: .htaccess

RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php/$1 [L]

db.php

<?php
$pdo = new PDO(
'mysql:host=localhost;dbname=test_db',
'root',
'',
[PDO::ATTR_EMULATE_PREPARES=>false]);

return $pdo;

MyHttpException.php

<?php

/**
 * 自定义异常
 * Class MyHttpException
 */
class MyHttpException extends Exception
{
    private $statusCode;// code状态码
    
    // $statusCode : code状态码
    public function __construct($statusCode, $message = '', $code = 0, $exception = null)
    {
        parent::__construct($message, $code, $exception);
        $this->statusCode = $statusCode;
    }

    // 得到状态码
    public function getStatusCode()
    {
        return $this->statusCode;
    }
}

Article.php

<?php
/**
 * 文章 Article.php
 */
require_once __DIR__ . '/MyHttpException.php';

class Article
{
   private $db = null;
   public function __construct(PDO $db)
   {
      $this->db = $db;
   }

   /**
    * 发表文章
    * @param string $title
    * @param string $content
    * @param integer $userId
    * @return array
    * @throws Exception
    */
   public function create($title, $content, $userId)
   {
      if (empty($title))
      {
         throw new MyHttpException(422, '标题不能为空');
      }
      if (empty($content))
      {
         throw new MyHttpException(422, '内容不能为空');
      }
      if (empty($userId))
      {
         throw new MyHttpException(422, '用户ID不能为空');
      }
      $sql = 'INSERT INTO `article` (`title`,`createdAt`,`content`,`userId`) VALUES (:title,:createdAt,:content,:userId)';
      $createdAt = time();
      $stmt = $this->db->prepare($sql);
      $stmt->bindParam(':title', $title);
      $stmt->bindParam(':content', $content);
      $stmt->bindParam(':userId', $userId);
      $stmt->bindParam(':createdAt', $createdAt);
      if (!$stmt->execute())
      {
         throw new MyHttpException(500, '发表失败');
      }
      return [
         'articleId' => $this->db->lastInsertId(),
         'title' => $title,
         'content' => $content,
         'createdAt' => $createdAt,
         'userId' => $userId
      ];
   }

   /**
    * 查看文章
    * @param integer $articleId
    * @return mixed
    * @throws Exception
    */
   public function view($articleId)
   {
      $sql = 'SELECT * FROM `article` WHERE `articleId`=:id';
      $stmt = $this->db->prepare($sql);
      $stmt->bindParam(':id', $articleId, PDO::PARAM_INT);
      $stmt->execute();
      $data = $stmt->fetch(PDO::FETCH_ASSOC);
      if (empty($data))
      {
         throw new MyHttpException(404, '文章不存在');
      }
      return $data;
   }

   /**
    * 编辑文章
    * @param integer $articleId
    * @param string $title
    * @param string $content
    * @param integer $userId
    * @return array
    * @throws Exception
    */
   public function update($articleId, $title, $content, $userId)
   {
      $article = $this->view($articleId);
      if ($article['userId'] != $userId)
      {
         throw new MyHttpException(403, '你没有权限修改该文章');
      }
      $sql = 'UPDATE `article` SET `title`=:title,`content`=:content WHERE articleId=:id';
      $stmt = $this->db->prepare($sql);
      $t = empty($title) ? $article['title'] : $title;
      $stmt->bindParam(':title', $t);
      $c =  empty($content) ? $article['content'] : $content;
      $stmt->bindParam(':content',$c);
      $stmt->bindParam(':id', $articleId);
      if (!$stmt->execute())
      {
         throw new MyHttpException(500, '编辑失败');
      }
      return [
         'articleId' => $articleId,
         'title' => $t,
         'content' => $c,
         'createdAt' => $article['createdAt'],
         'userId' => $userId
      ];
   }

   /**
    * 文章列表
    * @param string $userId
    * @param int $page
    * @param int $limit
    * @return array
    */
   public function all($userId, $page = 1, $limit = 10)
   {
      $sql = 'SELECT * FROM `article` WHERE `userId`=:userId ORDER BY `articleId` DESC LIMIT :offset,:limit';
      $offset = ($page - 1) * $limit;
      if ($offset < 0)
      {
         $offset = 0;
      }
      $stmt = $this->db->prepare($sql);
      $stmt->bindParam(':userId', $userId, PDO::PARAM_INT);
      $stmt->bindParam(':offset', $offset, PDO::PARAM_INT);
      $stmt->bindParam(':limit', $limit, PDO::PARAM_INT);
      $stmt->execute();
      return $stmt->fetchAll(PDO::FETCH_ASSOC);
   }

   /**
    * 删除文章
    * @param string $articleId
    * @param integer $userId
    * @throws Exception
    */
   public function delete($articleId, $userId)
   {
      $article = $this->view($articleId);
      if ($article['userId'] != $userId)
      {
         throw new MyHttpException(404, '文章不存在');
      }
      $sql = 'DELETE FROM `article` WHERE `articleId`=:articleId AND `userId`=:userId';
      $stmt = $this->db->prepare($sql);
      $stmt->bindParam(':articleId', $articleId);
      $stmt->bindParam(':userId', $userId);
      if (!$stmt->execute())
      {
         throw new MyHttpException(500, '删除失败');
      }
   }
}

User.php

<?php
/**
 * Project: imooc-1
 * User: xialeistudio
 * Date: 2016/9/16 0016
 * Time: 22:10
 */
require_once __DIR__ . '/MyHttpException.php';

class User
{
   /**
    * @var PDO
    */
   private $db = null;
   /**
    * @var string MD5加密混淆
    */
   private $salt = 'imooc';

   /**
    * User constructor.
    * @param PDO $db
    */
   public function __construct($db)
   {
      $this->db = $db;
   }


   /**
    * 注册
    * @param string $username
    * @param string $password
    * @return array
    * @throws Exception
    */
   public function register($username, $password)
   {
      $username = trim($username);
      if (empty($username))
      {
         throw new MyHttpException(422, '用户名不能为空');
      }
      $password = trim($password);
      if (empty($password))
      {
         throw new MyHttpException(422, '密码不能为空');
      }
      //检测是否存在该用户
      if ($this->isUsernameExists($username))
      {
         throw new MyHttpException(422, '用户名已存在');
      }
      $password = md5($password . $this->salt);
      $createdAt = time();
      if ($this->db === null)
      {
         throw new MyHttpException(500, '数据库连接失败');
      }
      $sql = 'INSERT INTO `user`(`username`,`password`,`createdAt`) VALUES(:username,:password,:createdAt)';
      $stmt = $this->db->prepare($sql);
      $stmt->bindParam(':username', $username);
      $stmt->bindParam(':password', $password);
      $stmt->bindParam(':createdAt', $createdAt);
      if (!$stmt->execute())
      {
         throw new MyHttpException(500, '注册失败');
      }
      $userId = $this->db->lastInsertId();
      return [
         'userId' => $userId,
         'username' => $username,
         'createdAt' => $createdAt
      ];
   }

   /**
    * 登录
    * @param string $username
    * @param string $password
    * @return array
    * @throws Exception
    */
   public function login($username, $password)
   {
      $sql = 'SELECT * FROM `user` WHERE `username`=:username';
      $stmt = $this->db->prepare($sql);
      $stmt->bindParam(':username', $username);
      $stmt->execute();
      $user = $stmt->fetch(PDO::FETCH_ASSOC);
      if (empty($user))
      {
         throw new MyHttpException(422, '用户名或密码错误');
      }
      if ($user['password'] != md5($password . $this->salt))
      {
         throw new MyHttpException(422, '用户名或密码错误');
      }
      //TOOD:使用授权表
      unset($user['password']);
      return $user;
   }

   /**
    * 检测用户名是否存在
    * @param $username
    * @return bool
    * @throws Exception
    */
   private function isUsernameExists($username)
   {
      if ($this->db === null)
      {
         throw new MyHttpException(500, '数据库连接失败');
      }
      $sql = 'SELECT userId FROM `user` WHERE username = :username';
      $stmt = $this->db->prepare($sql);
      $stmt->bindParam(':username', $username);
      $stmt->execute();
      $data = $stmt->fetch(PDO::FETCH_ASSOC);
      return !empty($data);
   }

   /**
    * 查看用户
    * @param $userId
    * @return mixed
    * @throws MyHttpException
    */
   public function view($userId)
   {
      $sql = 'SELECT * FROM `user` WHERE userId=:id';
      $stmt = $this->db->prepare($sql);
      $stmt->bindParam(':id', $userId, PDO::PARAM_INT);
      $stmt->execute();
      $data = $stmt->fetch(PDO::FETCH_ASSOC);
      if (empty($data))
      {
         throw new MyHttpException(404, '用户不存在');
      }
      return $data;
   }

   /**
    * 编辑
    * @param $userId
    * @param $password
    * @return mixed
    * @throws MyHttpException
    */
   public function update($userId, $password)
   {
      $user = $this->view($userId);
      if (empty($password))
      {
         throw new MyHttpException(422, '密码不能为空');
      }
      $sql = 'UPDATE `user` SET `password` = :password WHERE userId=:id';
      $stmt = $this->db->prepare($sql);
      $stmt->bindParam(':id', $userId);
      $password = md5($password . $this->salt);
      $stmt->bindParam(':password', $password);
      if (!$stmt->execute())
      {
         throw new MyHttpException(500, '编辑失败');
      }
      return $user;
   }
}

restful.php

SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;
SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='TRADITIONAL,ALLOW_INVALID_DATES';

CREATE SCHEMA IF NOT EXISTS `restful` DEFAULT CHARACTER SET utf8mb4 ;
USE `restful` ;

DROP TABLE IF EXISTS `restful`.`user` ;
CREATE TABLE IF NOT EXISTS `restful`.`user` (
  `userId` INT NOT NULL AUTO_INCREMENT COMMENT '用户ID',
  `username` VARCHAR(20) NOT NULL COMMENT '用户名',
  `password` CHAR(32) NOT NULL COMMENT '密码',
  `createdAt` INT NOT NULL COMMENT '注册时间',
  PRIMARY KEY (`userId`),
  UNIQUE INDEX `username` (`username` ASC),
  INDEX `createdAt` (`createdAt` ASC))
ENGINE = InnoDB;

DROP TABLE IF EXISTS `restful`.`article` ;
CREATE TABLE IF NOT EXISTS `restful`.`article` (
  `articleId` INT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '文章ID',
  `title` VARCHAR(40) NOT NULL COMMENT '标题',
  `createdAt` INT NOT NULL COMMENT '发表时间',
  `content` TEXT NOT NULL COMMENT '文章内容',
  `userId` INT NOT NULL COMMENT '用户ID',
  PRIMARY KEY (`articleId`),
  INDEX `title` (`title` ASC),
  INDEX `createdAt` (`createdAt` ASC),
  INDEX `fk_article_user_idx` (`userId` ASC),
  CONSTRAINT `fk_article_user`
    FOREIGN KEY (`userId`)
    REFERENCES `restful`.`user` (`userId`)
    ON DELETE NO ACTION
    ON UPDATE NO ACTION)
ENGINE = InnoDB;

DROP TABLE IF EXISTS `restful`.`session` ;
CREATE TABLE IF NOT EXISTS `restful`.`session` (
  `token` CHAR(8) NOT NULL COMMENT '会话token',
  `createdAt` INT NOT NULL COMMENT '登录时间',
  `expiresAt` INT NOT NULL COMMENT '过期时间',
  `userId` INT NOT NULL COMMENT '用户ID',
  PRIMARY KEY (`token`),
  INDEX `fk_session_user1_idx` (`userId` ASC),
  INDEX `createdAt` (`createdAt` ASC),
  INDEX `expires` (`expiresAt` ASC),
  CONSTRAINT `fk_session_user1`
    FOREIGN KEY (`userId`)
    REFERENCES `restful`.`user` (`userId`)
    ON DELETE NO ACTION
    ON UPDATE NO ACTION)
ENGINE = InnoDB;

SET SQL_MODE=@OLD_SQL_MODE;
SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;

index.php

<?php
require_once __DIR__ . '/../handler/User.php';
require_once __DIR__ . '/../handler/Article.php';
require_once __DIR__ . '/../handler/MyHttpException.php';

class Bridge
{
   private $user;// User
   private $article; // Article
   private $method;// 请求方法
   private $entity;// 请求实体
   private $id; // 资源id
   private $allowEntities = ['users', 'articles'];
   private $allowMethods = ['GET', 'POST', 'PUT', 'OPTIONS', 'HEAD', 'DELETE'];
   public function __construct()
   {
      $pdo = require_once __DIR__ . '/../db.php';
      $this->user = new User($pdo);
      $this->article = new Article($pdo);
      $this->setupRequestMethod();
      $this->setupEntity();
   }

   /**
    * 初始化实体
    */
   private function setupEntity()
   {
      $pathinfo = $_SERVER['PATH_INFO'];
      if (empty($pathinfo))
      {
         static::sendHttpStatus(400);
      }
      $params = explode('/', $pathinfo);
      $this->entity = $params[1];
      if (!in_array($this->entity, $this->allowEntities))
      {
         //实体不存在
         static::sendHttpStatus(404);
      }
      if (!empty($params[2]))
      {
         $this->id = $params[2];
      }
   }

   /**
    * 发送HTTP响应状态码
    * @param $code
    * @param string $error
    * @param array|null $data
    * @internal param null $message
    */
   static function sendHttpStatus($code, $error = '', $data = null)
   {
      static $_status = array(
         // Informational 1xx
         100 => 'Continue',
         101 => 'Switching Protocols',
         // Success 2xx
         200 => 'OK',
         201 => 'Created',
         202 => 'Accepted',
         203 => 'Non-Authoritative Information',
         204 => 'No Content',
         205 => 'Reset Content',
         206 => 'Partial Content',
         // Redirection 3xx
         300 => 'Multiple Choices',
         301 => 'Moved Permanently',
         302 => 'Found',  // 1.1
         303 => 'See Other',
         304 => 'Not Modified',
         305 => 'Use Proxy',
         // 306 is deprecated but reserved
         307 => 'Temporary Redirect',
         // Client Error 4xx
         400 => 'Bad Request',
         401 => 'Unauthorized',
         402 => 'Payment Required',
         403 => 'Forbidden',
         404 => 'Not Found',
         405 => 'Method Not Allowed',
         406 => 'Not Acceptable',
         407 => 'Proxy Authentication Required',
         408 => 'Request Timeout',
         409 => 'Conflict',
         410 => 'Gone',
         411 => 'Length Required',
         412 => 'Precondition Failed',
         413 => 'Request Entity Too Large',
         414 => 'Request-URI Too Long',
         415 => 'Unsupported Media Type',
         416 => 'Requested Range Not Satisfiable',
         417 => 'Expectation Failed',
         422 => 'Unprocessable Entity',
         // Server Error 5xx
         500 => 'Internal Server Error',
         501 => 'Not Implemented',
         502 => 'Bad Gateway',
         503 => 'Service Unavailable',
         504 => 'Gateway Timeout',
         505 => 'HTTP Version Not Supported',
         509 => 'Bandwidth Limit Exceeded'
      );
      if (isset($_status[$code]))
      {
          // HTTP/1.1 405 Method Not Allowed
         header('HTTP/1.1 ' . $code . ' ' . $_status[$code]);
         header('Content-Type:application/json;charset=utf-8');
         if ($code == 200) //2xx状态码
         {
            echo json_encode($data, JSON_UNESCAPED_UNICODE);
         }
         else if ($code == 204)
         {
            //无响应体
         }
         else
         {
            if (empty($error))
            {
               $error = $_status[$code];
            }
            echo json_encode(['error' => $error], JSON_UNESCAPED_UNICODE);
         }
      }
      exit(0);
   }

   /**
    * 初始化请求方法
    */
   private function setupRequestMethod()
   {
      $this->method = $_SERVER['REQUEST_METHOD'];
      if (!in_array($this->method, $this->allowMethods))
      {
         //请求方法不被允许
         static::sendHttpStatus(405);
      }
   }

   /**
    * 处理请求
    */
   public function handle()
   {
      try
      {
         if ($this->entity == 'users')
         {
            $this->handleUser();
         }
         if ($this->entity == 'articles')
         {
            $this->handleArticle();
         }
      }
      catch (MyHttpException $e)
      {
         static::sendHttpStatus($e->getStatusCode(), $e->getMessage());
      }
   }

   /**
    * 获取请求体
    * @return mixed|null
    */
   private function getBodyParams()
   {
      $raw = file_get_contents('php://input');
      if (empty($raw))
      {
         return [];
      }
      return json_decode($raw, true);
   }

   private function getBodyParam($name, $defaultValue = null)
   {
      $data = $this->getBodyParams();
      return isset($data[$name]) ? $data[$name] : $defaultValue;
   }

   /**
    * 要求认证
    * @return bool|array
    * @throws MyHttpException
    */
   private function requestAuth()
   {
      if (!empty($_SERVER['PHP_AUTH_USER']) && !empty($_SERVER['PHP_AUTH_PW']))
      {
         try
         {
            $user = $this->user->login($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']);
            return $user;
         }
         catch (MyHttpException $e)
         {
            if ($e->getStatusCode() != 422)
            {
               throw $e;
            }
         }
      }
      // 实现basic认证
      header("WWW-Authenticate:Basic realm='Private'");
      header('HTTP/1.0 401 Unauthorized');
      print "You are unauthorized to enter this area.";
      exit(0);
   }

   /**
    * 处理访问用户的请求
    */
   private function handleUser()
   {
      if ($this->method == 'GET')
      {
         if (empty($this->id))
         {
            //客户端需要获取所有用户的信息,访问有效,但是无权限
            throw new MyHttpException(403);
         }
         static::sendHttpStatus(200, null, $this->user->view($this->id));
      }
      else if ($this->method == 'POST')
      {
         $data = $this->getBodyParams();
         if (empty($data['username']))
         {
            throw new MyHttpException(422, '用户名不能为空');
         }
         if (empty($data['password']))
         {
            throw new MyHttpException(422, '密码不能为空');
         }
         static::sendHttpStatus(200, null, $this->user->register($data['username'], $data['password']));
      }
      else if ($this->method == 'PUT')
      {
         if (empty($this->id))
         {
            throw new MyHttpException(400);
         }
         $params = $this->getBodyParams();
         if (empty($params) || empty($params['password']))
         {
            throw new MyHttpException(422, '密码不能为空');
         }
         //检测认证参数
         $user = $this->requestAuth();
         $result = $this->user->update($user['userId'], $params['password']);
         static::sendHttpStatus(200, null, $result);
      }
      else
      {
         throw new MyHttpException(405);
      }
   }

   private function getQueryParam($name, $defaultValue = null)
   {
      return isset($_GET[$name]) ? $_GET[$name] : $defaultValue;
   }

   /**
    * 处理访问文章的请求
    */
   private function handleArticle()
   {
      if ($this->method == 'GET')
      {
         $user = $this->requestAuth();
         if (empty($this->id))
         {
            $list = $this->article->all($user['userId'], $this->getQueryParam('page', 1), $this->getQueryParam('size', 10));
            self::sendHttpStatus(200, null, $list);
         }
         self::sendHttpStatus(200, null, $this->article->view($this->id));
      }
      else if ($this->method == 'POST')
      {
         $user = $this->requestAuth();
         $data = $this->getBodyParams();
         if (empty($data['title']))
         {
            throw new MyHttpException(422, '标题不能为空');
         }
         if (empty($data['content']))
         {
            throw new MyHttpException(422, '内容不能为空');
         }
         $article = $this->article->create($data['title'], $data['content'], $user['userId']);
         static::sendHttpStatus(200, null, $article);
      }
      else if ($this->method == 'PUT')
      {
         if (empty($this->id))
         {
            throw new MyHttpException(400);
         }
         $user = $this->requestAuth();
         $data = $this->getBodyParams();
         $title = isset($data['title']) ? $data['title'] : null;
         $content = isset($data['content']) ? $data['content'] : null;
         $article = $this->article->update($this->id, $title, $content, $user['userId']);
         static::sendHttpStatus(200, null, $article);
      }
      else if ($this->method == 'DELETE')
      {
         if (empty($this->id))
         {
            throw new MyHttpException(400);
         }
         $user = $this->requestAuth();
         $this->article->delete($this->id, $user['userId']);
         static::sendHttpStatus(204, null, null);
      }
   }
}


$bridge = new Bridge();
$bridge->handle();



1.php

<?php

class Restful
{
    private $resouce;// 资源名称
    private $id; // 资源id
    private $requestMethod; // 请求的类型
    private $setupRequestMethod;// 设置请求的类型
    private $allowResouces = array("users", "aticles");
    private $allowMethods = array("GET", "POST", "PUT", "DELETE", "OPTIONS");
    // http状态码
    private $statusCodes = array(
        200 => "OK",
        204 => "No Content",
        400 => "Bad Request",
        401 => "Unauthorized",
        403 => "Forbidden",
        404 => "Not Found",
        405 => "Method Not Allowed",
        500 => "Server Internal Error",
    );

    // 初始化资源标识符
    private function setupId(){}

    /**
     * 返回的json字符串
     * @param $array
     * @param int $code
     */
    private function json($array, $code = 0)
    {
        // 对于a标签,如果链接的页面响应码为204,页面也不会发生跳转
        if ($code > 0 && $code != 200 && $code != 204) {
            // http/1.1 405 Method Not Allowed
            header("HTTP/1.1 " . $code . " " . $this->statusCodes[$code]);
        }
        header("Content-Type:application/json;charset=utf-8");
        // JSON_UNESCAPED_UNICODE 将json转为中文,而不是ASCII码
        echo json_encode($array, JSON_UNESCAPED_UNICODE);
        exit();
    }

    // 初始化请求方法
    private function setupRequestMethod()
    {
        // 请求传递数据的方式
        $this->setupRequestMethod = $_SESSION['REQUEST_METHOD'];
        // $this->allowMethods array("GET", "POST", "PUT", "DELETE", "OPTIONS");
        if (!in_array($this->setupRequestMethod, $this->allowMethods)) {
            throw new Exception('请求方法不被允许', 405);
        }
    }

    //初始化请求资源
    private function setupResource()
    {
        $path = $_SESSION['PATH_INFO'];
        $params = explode("/", $path);
        // 请求资源url
        $this->resouce = $params[1];// api.baidu.com//post/
        if (!in_array($this->resouce, $this->allowResouces)) {
            throw new Exception("请求资源不被允许", 405);
        }
        if (!empty($params[2])) {
            // 请求资源的id
            $this->id = $params[2];
        }
    }

    /*****************************************************************************/
    private function handleUser()
    {
        if ($this->requestMethod !="POST"){
            throw new Exception("请求方法不被允许",405);
        }
        $body = $this->getBodyParams();
        if (empty($body['username'])){
            throw new Exception("不能为空",400);
        }
        if (empty($body['password'])){
            throw new Exception("不能为空",400);
        }

        return $this->user->register($body['username'],$body['password']);
    }

    private function handleArticle()
    {
        switch ($this->requestMethod){
            case "POST":
                return $this->create();
                break;
            case "PUT":
                return $this->edit();
                break;
            case "DELETE":
                return $this->delete();
                break;
            case "GET":
                if ($this->id){
                    return $this->list();
                }else{
                    return $this->view();
                }

                break;
        }

    }

    // 获取请求体
    private function getBodyParams(){
        /**
         * 参考:https://blog.****.net/stand_forever/article/details/81736175
         * php://input 不能用于 enctype="multipart/form-data"
         * php://input读取不到$_GET数据
         * php://input 通过输入流以文件读取方式取得未经处理的POST原始数据
         */
        $rows = file_get_contents('php://input');
        if (empty($rows)){
           throw new Exception("请求参数错误",400);
        }
        return json_decode($rows,true);
    }

    public function run()
    {
        try {
            $this->setupRequestMethod();
            $this->setupResource();
            $this->setupId();
            if ($this->resouce == "users") {
                return $this->handleUser();
            } else {
                return $this->handleArticle();
            }
        } catch (Exception $e) {
            $this->json(array('error' => $e->getMessage()), $e->getCode());
        }
    }
}

$article = new Article($pdo);
$user = new User($pdo);

$restful = new Restful($user, $article);
$restful->run();
上一篇:SQL预编译


下一篇:JDBC入门笔记(详解)