PHP面向对象编程基础
面向对象编程(OOP)是一种编程范式,它使用”对象”来设计应用程序和软件。PHP从版本5开始全面支持OOP特性。
类和对象
类是对象的蓝图,对象是类的实例。下面是一个简单的PHP类示例:
<?php
class Post {
// 属性
private $id;
private $title;
private $content;
private $createdAt;
// 构造方法
public function __construct($title, $content) {
$this->title = $title;
$this->content = $content;
$this->createdAt = date('Y-m-d H:i:s');
}
// 方法
public function getExcerpt($length = 150) {
if (strlen($this->content) > $length) {
return substr($this->content, 0, $length) . '...';
}
return $this->content;
}
// Getter和Setter方法
public function getTitle() {
return $this->title;
}
public function setTitle($title) {
$this->title = $title;
}
// 其他getter和setter方法...
}
?>
面向对象的三大特性
- 封装:将数据和行为捆绑在一起,并隐藏内部实现细节
- 继承:允许一个类继承另一个类的属性和方法
- 多态:同一操作作用于不同类的实例,产生不同的执行结果
MVC设计模式详解
MVC(Model-View-Controller)是一种软件设计模式,将应用程序分为三个核心组件:
模型(Model)
负责数据和业务逻辑,与数据库交互,处理数据验证和存储。
视图(View)
负责呈现用户界面,显示数据并接收用户输入。
控制器(Controller)
处理用户请求,协调模型和视图,决定如何响应请求。
MVC工作流程
- 用户通过视图发出请求
- 控制器接收请求并调用相应的模型处理
- 模型进行数据操作并返回结果
- 控制器选择适当的视图呈现数据
- 视图渲染页面并返回给用户
实现博客系统
下面我们将使用PHP OOP和MVC模式实现一个简单的博客系统。
项目结构
blog-system/
│
├── app/
│ ├── controllers/
│ │ └── PostController.php
│ ├── models/
│ │ └── Post.php
│ └── views/
│ ├── posts/
│ │ ├── index.php
│ │ └── show.php
│ └── layout.php
│
├── config/
│ └── database.php
│
└── public/
└── index.php
数据库配置 (config/database.php)
<?php
class Database {
private $host = 'localhost';
private $db_name = 'blog';
private $username = 'root';
private $password = '';
public $conn;
public function getConnection() {
$this->conn = null;
try {
$this->conn = new PDO(
"mysql:host=" . $this->host . ";dbname=" . $this->db_name,
$this->username,
$this->password
);
$this->conn->exec("set names utf8");
} catch(PDOException $exception) {
echo "Connection error: " . $exception->getMessage();
}
return $this->conn;
}
}
?>
文章模型 (app/models/Post.php)
<?php
class Post {
private $conn;
private $table_name = "posts";
public $id;
public $title;
public $content;
public $created_at;
public function __construct($db) {
$this->conn = $db;
}
public function read() {
$query = "SELECT * FROM " . $this->table_name . " ORDER BY created_at DESC";
$stmt = $this->conn->prepare($query);
$stmt->execute();
return $stmt;
}
public function create() {
$query = "INSERT INTO " . $this->table_name .
" SET title=:title, content=:content, created_at=:created_at";
$stmt = $this->conn->prepare($query);
// 清理数据
$this->title = htmlspecialchars(strip_tags($this->title));
$this->content = htmlspecialchars(strip_tags($this->content));
$this->created_at = date('Y-m-d H:i:s');
// 绑定参数
$stmt->bindParam(":title", $this->title);
$stmt->bindParam(":content", $this->content);
$stmt->bindParam(":created_at", $this->created_at);
if ($stmt->execute()) {
return true;
}
return false;
}
// 其他方法:update, delete, readSingle等...
}
?>
文章控制器 (app/controllers/PostController.php)
<?php
class PostController {
private $postModel;
public function __construct($db) {
$this->postModel = new Post($db);
}
public function index() {
// 获取所有文章
$stmt = $this->postModel->read();
$num = $stmt->rowCount();
// 检查是否有文章
if ($num > 0) {
$posts_arr = array();
$posts_arr["data"] = array();
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
extract($row);
$post_item = array(
"id" => $id,
"title" => $title,
"content" => html_entity_decode($content),
"created_at" => $created_at
);
array_push($posts_arr["data"], $post_item);
}
// 设置响应码 - 200 OK
http_response_code(200);
// 显示文章数据
return $posts_arr;
} else {
// 设置响应码 - 404 Not found
http_response_code(404);
// 没有文章
return array("message" => "没有找到文章");
}
}
public function show($id) {
// 获取单篇文章
$this->postModel->id = $id;
$this->postModel->readSingle();
if ($this->postModel->title != null) {
$post_arr = array(
"id" => $this->postModel->id,
"title" => $this->postModel->title,
"content" => $this->postModel->content,
"created_at" => $this->postModel->created_at
);
// 设置响应码 - 200 OK
http_response_code(200);
// 显示文章数据
return $post_arr;
} else {
// 设置响应码 - 404 Not found
http_response_code(404);
// 没有文章
return array("message" => "文章不存在");
}
}
// 其他方法:create, update, delete等...
}
?>
前端控制器 (public/index.php)
<?php
// 包含配置文件和模型
include_once '../config/database.php';
include_once '../app/models/Post.php';
include_once '../app/controllers/PostController.php';
// 设置响应头为JSON
header("Access-Control-Allow-Origin: *");
header("Content-Type: application/json; charset=UTF-8");
// 实例化数据库连接
$database = new Database();
$db = $database->getConnection();
// 实例化控制器
$postController = new PostController($db);
// 获取请求方法和参数
$method = $_SERVER['REQUEST_METHOD'];
$request = explode('/', trim($_SERVER['PATH_INFO'],'/'));
$input = json_decode(file_get_contents('php://input'), true);
// 路由请求
switch ($method) {
case 'GET':
if (isset($request[0]) && is_numeric($request[0])) {
// 获取单篇文章
$result = $postController->show($request[0]);
} else {
// 获取所有文章
$result = $postController->index();
}
break;
case 'POST':
// 创建新文章
$result = $postController->create($input);
break;
case 'PUT':
// 更新文章
if (isset($request[0]) && is_numeric($request[0])) {
$result = $postController->update($request[0], $input);
}
break;
case 'DELETE':
// 删除文章
if (isset($request[0]) && is_numeric($request[0])) {
$result = $postController->delete($request[0]);
}
break;
default:
// 方法不被允许
header("HTTP/1.1 405 Method Not Allowed");
exit;
}
// 输出结果
echo json_encode($result);
?>
安全考虑和最佳实践
在开发PHP应用程序时,安全性是至关重要的考虑因素。
SQL注入防护
使用预处理语句和参数化查询来防止SQL注入攻击:
// 不安全的做法
$query = "SELECT * FROM users WHERE username = '" . $_POST['username'] . "'";
// 安全的做法 - 使用预处理语句
$stmt = $conn->prepare("SELECT * FROM users WHERE username = :username");
$stmt->bindParam(':username', $_POST['username']);
$stmt->execute();
XSS跨站脚本防护
对输出进行转义,防止恶意脚本执行:
// 输出前转义HTML特殊字符
echo htmlspecialchars($user_input, ENT_QUOTES, 'UTF-8');
CSRF跨站请求伪造防护
使用CSRF令牌验证请求的合法性:
// 生成CSRF令牌
if (empty($_SESSION['csrf_token'])) {
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}
// 在表单中包含CSRF令牌
echo '<input type="hidden" name="csrf_token" value="' . $_SESSION['csrf_token'] . '">';
// 验证CSRF令牌
if (!empty($_POST['csrf_token'])) {
if (hash_equals($_SESSION['csrf_token'], $_POST['csrf_token'])) {
// 令牌有效,处理请求
} else {
// 令牌无效,拒绝请求
}
}
密码安全
使用PHP password_hash函数安全地存储密码:
// 创建密码哈希
$hashed_password = password_hash($password, PASSWORD_DEFAULT);
// 验证密码
if (password_verify($input_password, $hashed_password)) {
// 密码正确
} else {
// 密码错误
}