1.后期(延迟)静态绑定
- 在创建类层次结构时,self关键字在编译时就已经确定了它的作用范围,而不是在运行时(后期),self不能动态地与调用类进行绑定。解决办法:用static替换self进行后期(延迟)静态绑定。
- $this能动态地与调用类进行绑定。
<?php
/**
* 后期(延迟)静态绑定 static
*
*/
class sports
{
// 静态属性
public static $sport_event = '足球';
// 静态方法
public static function live_TV()
{
// 用self引用静态属性
echo '正在直播' . self::$sport_event . '节目。<br>';
// 用static引用静态属性
echo '回放' . static::$sport_event . '节目。<br>';
}
}
// 继承sports类
class basketball extends sports
{
// 重定义静态属性
public static $sport_event = '篮球';
}
echo sports::live_TV();
echo basketball::live_TV();
// 结果说明self不能动态地与调用类进行绑定,用static可以。
2. 单例模式: 只允许类被实例化一次
// 单例模式 只允许类被实例化一次
class father
{
// 只可子类访问的静态属性,用于存贮类的实例
protected static $_class;
// 定义构造函数不可用
private function __construct()
{
}
// 定义克隆函数不可用
private function __clone()
{
}
// 获取类的实例函数
static function get_class()
{
// 存贮类实例的变量不存在,则实例化类并存入变量。
if (static::$_class === null) {
static::$_class = new static;
}
// 返回实例对象
return static::$_class;
}
}
class son1 extends father
{
protected static $_class;
}
class son2 extends father
{
protected static $_class;
}
var_dump($a1 = father::get_class());
var_dump($a2 = son1::get_class());
var_dump($a3 = son2::get_class());
var_dump($b1 = father::get_class());
var_dump($b2 = son1::get_class());
var_dump($b3 = son2::get_class());
var_dump($a = new basketball);
var_dump($b = new basketball);
var_dump($a1 === $b1);
var_dump($a2 === $b2);
var_dump($a3 === $b3);
var_dump($a === $b);
从显示结果可以看到,单例模式只能实例化一次,多次实例化的都是同一个类。
3. php重载
- php重载 属性, 是指动态地创建类属性和方法。我们是通过魔术方法(magic methods)来实现的。
__get __set __callStatic __call
- 当访问类中不存在或者不可见的类成员时,会自动调用魔术方法set get
- 因为魔术方法都是公开的,所以一些私有成员的不可见性就不会生效
<?php
/**
* php重载 overload
*
*/
class Id_card
{
public $name; // 姓名属性可公开
private $id; // 身份证号不可公开
public function __construct($name, $id)
{
$this->name = $name;
$this->id = $id;
}
// 这个魔术方法是系统带有的,这里可以注释掉
public function __set($name, $value)
{
$this->$name = $value;
return $this->$name;
}
// 这个魔术方法是系统带有的,这里可以注释掉
public function __get($name)
{
return $this->$name;
}
}
$id = new Id_card('成龙', '486136196501221035');
var_dump($id);
$id->age = 68; // 自动执行魔术方法__set
echo $id->age; // 自动执行__get
// 类没有定义age属性,但系统会自动执行魔术方法,这就是重载
echo $id->id; // 虽然id属性定义了不可公开,但是系统自动执行__get方法,导致定义失效
3. 单例模式连接数据库
<?php
/**
* 单例模式连接数据库
*/
namespace DB\pdo {
// 使用了命名空间,因此要使用系统pdo对象就要引用
use pdo, PDOException, Exception;
// 定义数据库查询通用接口
interface DB_query
{
// 连接数据库接口方法
static function do_conn($dsn, $username, $password);
// 查询数据库接口方法
static function select($table, $where = []);
// 插入数据接口方法
static function insert($table, $date);
// 更新数据接口方法
static function update($table, $date, $where);
// 删除数据接口方法
static function delete($table, $where);
}
/**
* 定义数据库连接抽象类,采用数据库查询通用接口DB_query
* 使用单例模式实现连接数据库
*/
abstract class DB_conn implements DB_query
{
protected static $pdo; // 存放连接数据库pdo对象
// 禁用魔术方法
private function __construct()
{
}
private function __clone()
{
}
// 创建唯一实例,存放pdo对象
static function do_conn($dsn, $username, $password)
{
// 判断属性$pdo是否存在,不存在则创建pdo对象
if (is_null(self::$pdo)) {
// 创建pdo,进行错误识别
try {
self::$pdo = new PDO($dsn, $username, $password);
return self::$pdo;
} catch (PDOException $err) {
//PDOException异常类,指定变量$err为异常类型变量;
die('错误:' . $err->getMessage());
}
}
}
}
/**
* 定义工作类,实现接口方法
*
*/
class DB extends DB_conn
{
private static $sql;
private static $sql_state;
// 预处理查询操作
static function do_sql($sql)
{
if (!is_null(self::$pdo)) {
$stmt = self::$pdo->prepare($sql);
$stmt->execute();
self::$sql_state = ($stmt->rowCount() > 0) ? true : false;
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
}
// 查询数据库接口方法
static function select($table, $where = [])
{
if (count($where) < 1) {
$where = '';
} else {
$where = "WHERE {$where[0]}{$where[1]}'{$where[2]}'";
}
self::$sql = "SELECT * FROM `{$table}` {$where}";
var_dump(self::$sql);
return self::do_sql(self::$sql);
}
// 插入数据接口方法
static function insert($table, $date = [])
{
$keys = '';
$values = [];
if (count($date) > 0) {
$keys = implode(',', array_keys($date));
foreach ($date as $key => $value) {
$values[] = "'{$value}'";
}
$values = implode(',', $values);
}
self::$sql = "INSERT INTO `{$table}` ({$keys}) VALUES ({$values})";
try {
self::do_sql(self::$sql);
echo "插入数据成功!";
} catch (Exception $err) {
echo '插入数据失败';
}
}
// 更新数据接口方法
static function update($table, $date, $where)
{
$dates = [];
if (count($date) > 0) {
foreach ($date as $key => $value) {
$dates[] = " $key =' $value ' ";
}
$dates = implode(',', $dates);
}
self::$sql = "UPDATE `$table` SET $dates WHERE $where";
// var_dump(self::$sql);
try {
self::do_sql(self::$sql);
if (self::$sql_state) {
echo "更新数据成功!";
} else {
echo '更新数据失败';
}
} catch (Exception $err) {
echo '更新数据失败';
}
}
// 删除数据接口方法
static function delete($table, $where)
{
self::$sql = "DELETE FROM `$table` WHERE $where";
try {
self::do_sql(self::$sql);
if (self::$sql_state) {
echo "删除数据成功!<br>";
} else {
echo '删除数据失败<br>';
}
} catch (Exception $err) {
echo '删除数据失败<br>';
}
}
}
// mysql数据库类
class DB_mysql
{
public static $dsn;
public static $username;
public static $password;
private static $DB_config = [
'DB_type' => 'mysql', // 连接数据库类型名
'host' => 'localhost', // 数据库服务器名
'port' => '3308', // 数据库数据库服务器端口
'dbname' => 'php', // 数据库名
'charset' => 'utf8mb4', // 字符集
'username' => 'root', // 数据库服务器用户名
'password' => '', // 数据库服务器密码
];
// 禁用魔术方法
private function __construct()
{
}
private function __clone()
{
}
static function get_dsn()
{
// 用extract()函数将数组转为变量,即数组索引为变量名
extract(self::$DB_config);
self::$username = $username;
self::$password = $password;
// 用sprintf格式化字符串,用占位符代入变量
self::$dsn = sprintf('%s:host=%s;port=%s;charset=%s;dbname=%s', $DB_type, $host, $port, $charset, $dbname);
}
}
}
// 客户端代码
namespace user {
use DB\pdo\DB_mysql, DB\pdo\DB;
DB_mysql::get_dsn();
DB::do_conn(DB_mysql::$dsn, DB_mysql::$username, DB_mysql::$password);
var_dump(DB::select('user', ['name', '=', '小李']));
DB::insert('user', ['name' => '小王', 'pass' => '7c4a8d09ca3762af61e59520943dc26494f8941b', 'gender' => 1]);
DB::update('user', ['name' => '小s', 'gender' => 1], 'id=8');
DB::delete('user', 'id=9');
}