需要的数据库
CREATE TABLE `user` ( `uid` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '用户ID', `name` varchar(50) NOT NULL COMMENT '姓名', `age` smallint(3) unsigned NOT NULL COMMENT '年龄', PRIMARY KEY (`uid`) ) ENGINE=MyISAM AUTO_INCREMENT=7 DEFAULT CHARSET=utf8; INSERT INTO `user` VALUES ('1', '欧阳克', '18'); INSERT INTO `user` VALUES ('2', '老顽童', '50'); INSERT INTO `user` VALUES ('3', '黄蓉', '33'); INSERT INTO `user` VALUES ('4', '郭靖', '18'); INSERT INTO `user` VALUES ('5', '一灯大师', '80'); INSERT INTO `user` VALUES ('6', '洪七公', '79');
# 创建类 class Animal{ } # 调用类(实例化) $monkey = new Animal(); // 猴子 $rabbit = new Animal(); // 兔子
[danger] 备:类如果只能使用一次,那我们没必须用类,每次直接写代码就可以了。所以类可以实例化多次(N次),次数无限制。
var_dump($monkey == $rabbit); echo '<br>'; var_dump($monkey === $rabbit); echo '<br>';
var_dump($monkey instanceof Animal); echo '<br>';
在类里直接写代码,是错误的
# 错误示例 class Animal{ echo 111; }
class People{ $name = '杨幂'; //会报错,必须有修饰符 $age = 31; //会报错,必须有修饰符 // 属性 设置了初始值 public $name = '杨幂'; public $age = 31; } # 外部访问:需要通过访问限定符、或修饰符 $yangmi = new People; echo $yangmi->name;
属性重新赋值
$yangmi->name = '欧阳克'; $yangmi->age = 18; echo $yangmi->name.$yangmi->age;
class People{ // 属性 public $name = '杨幂'; public $age = 31; // 方法,默认就是public ,不加也是 public function getInfo(){ echo '姓名:杨幂,年龄:31'; return '姓名:杨幂,年龄:31'; } // 方法 public function getInfo1(){ // self : 当前类 $obj = new self(); // 输出对象属性 return '姓名: ' .$obj->name .', 年龄: ' . $obj->age . '<br>'; } // 方法 public function getInfo2(){ // 因为该方法必须通过对象调用,所有没必要在类中实例化 // 直接引用该类的实例化对象即可 // 在类中使用伪变量: "$this" 引用当前类的实例 // $this = new self(); 相当于先执行了这条语句,尽管你不需要这样做 return '姓名: ' .$this->name .', 年龄: ' . $this->age . '<br>'; } // 方法 public function getInfo3(){ // 当前类 $obj = new People(); $obj->name = '欧阳克'; $obj->age = 18; // 输出对象属性 return '姓名: ' .$obj->name .', 年龄: ' . $obj->age . '<br>'; } } // 类实例化 $yangmi = new People(); echo $yangmi->getInfo(); echo $yangmi->getInfo1(); echo $yangmi->getInfo2(); echo $yangmi->getInfo3(); // 查看类中定义的对象方法: public 才会显示出来 $methods = get_class_methods('People'); echo '<pre>'.print_r($methods,true); echo '<hr>';
public function __construct(){...} ,也可以跟类名一样的方法class People{ // 属性 public $name; public $age; // 构造方法 public function __construct($name, $age){ echo '开始执行'; $this->name = $name; $this->age = $age; } // 方法 public function getInfo(){ return '姓名: ' .$this->name .', 年龄: ' . $this->age . '<br>'; } } // 实例化 $obj = new People('杨幂',31); echo $obj->getInfo();
public function __destruct(){...} ,也可以跟类名一样的方法class People{ // 属性 public $name; public $age; // 构造方法 public function __construct($name, $age){ echo '开始执行'; $this->name = $name; $this->age = $age; } // 方法 public function getInfo(){ return '姓名: ' .$this->name .', 年龄: ' . $this->age . '<br>'; } // 析构方法 public function __destruct(){ echo '类执行完毕,要关闭了'; } } // 实例化 $obj = new People('杨幂',31); echo $obj->getInfo(); $obj = null; // 如果没有手动释放,就会在最后执行析构方法
实战:自动连接数据库
class Db{ // 连接参数 public $dsn; public $user; public $password; // 连接属性 public $pdo; // 连接方法 public function connect(){ // 使用PDO方式管理数据库, 连接成功则返回PDO对象,赋值给对象属性pdo $this->pdo = new PDO($this->dsn, $this->user, $this->password); } // 希望在实例化时, 自动连接数据库, 这个需求很常见 public function __construct($dsn, $user, $password){ // 初始化对象属性 $this->dsn = $dsn; $this->user = $user; $this->password = $password; // 自动调用对象方法,连接数据库 $this->connect(); } // 析构方法 public function __destruct(){ $this->pdo = null; } } // 实例化 $db = new Db('mysql:host=localhost;dbname=ouyangke', 'root', 'root'); if ($db->pdo) { echo '<h2>连接成功</h2>'; } // 读取数据库测试 $stmt = $db->pdo->prepare('select * from user'); $stmt->execute(); foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $user) { print_r($user); echo '<br>'; }
class People{ // 对象属性 public $name; public $age; // 构造方法 public function __construct($name, $age){ $this->name = $name; $this->age = $age; } // 方法 public function getInfo(){ return '姓名: ' .$this->name .', 年龄: ' . $this->age; } } // 子类Sub1, 代码复用 class Woman extends People{ // ... } // 实例化子类Woman, 尽管子类中无任何成员,但是它可以直接调用父类People中的全部成员 $sub1 = new Woman('杨幂', 31); echo $sub1->getInfo() . '<br>';
实现子类里的方法
// 子类Woman, 增加属性和方法,扩展父类功能 class Woman extends People{ public $wages; // 工资 // 子类的构造方法 public function __construct($name, $age, $wages){ // 调用父类的构造方法,否则还要手工把父类中的属性初始化语句全部写一遍 // parent:: 调用被覆写的父类方法内容 parent::__construct($name, $age); // 只需要添加子类中的成员初始化代码 $this->wages = $wages; } // 计算一年工资 public function total(){ return $this->wages*12; } } // 实例化子类 $sub2 = new Woman('杨幂',31,500000); echo $sub2->name . '的年薪: ' . $sub2->total() . '<br>';
子类重写父类方法
// 如果父类有这个方法,子类也用了这个方法 // 第三个子类, 继承自Woman, 而Star又继承自People,这就形成了多层给的继承关系 class Star extends Woman{ // 重写父类total()方法 public function total(){ $total = parent::total(); // 判断工资单位 switch ($total) { case $total>100000000: $total = ($total/10000).'亿'; break; case $total>10000: $total = ($total/10000).'万'; break; default: $total = $total; break; } return $total; } } // 实例化子类 $sub3 = new Star('杨幂',31,500000); echo $sub3->name . '的年薪: ' . $sub3->total() . '<br>'; echo '<hr>';
成员(变量)的封装
class Woman{ // 属性 public $name; // 姓名 protected $age; // 年龄 private $wages; // 工资 // 构造方法 public function __construct($name, $age, $wages){ $this->name = $name; $this->age = $age; $this->wages = $wages; } } // 类实例化 $obj = new Woman('杨幂',31,500000); echo $obj->name, '<br>'; // echo $obj->age, '<br>'; // 会报错 // echo $obj->wages, '<br>'; // 会报错 // 继承后访问 class Star extends Woman{ public function info(){ echo $this->name, '<br>'; echo $this->age, '<br>'; // echo $this->wages, '<br>'; // 会报错 } } // 类实例化 $obj1 = new Star('baby',28,400000); echo $obj1->name, '<br>'; // echo $obj->age, '<br>'; // 会报错 // echo $obj->wages, '<br>'; // 会报错 echo $obj1->info(); echo '<hr>';
行为(方法)的封装
class Woman{ // 属性 public $name; // 姓名 protected $age; // 年龄 private $wages; // 工资 // 构造方法 public function __construct($name, $age, $wages){ $this->name = $name; $this->age = $age; $this->wages = $wages; } public function name(){ return '我的名字叫:'.$this->name.'<br>'; } protected function age(){ return '我的年龄是:'.$this->age.'<br>'; } private function wages(){ return '我的工资是:'.$this->wages.'<br>'; } public function all(){ echo $this->name(); echo $this->age(); echo $this->wages(); } } // 类实例化 $obj = new Woman('杨幂',31,500000); echo $obj->name(); //echo $obj->age(); // 会报错 //echo $obj->wages(); // 会报错 echo $obj->all(); class Star extends Woman{ public function info(){ echo $this->name(); echo $this->age(); // echo $this->wages(); //私有的会报错 } public function a(){ echo $this->all(); } } // 类实例化 $obj1 = new Star('baby',28,400000); echo $obj1->a(); echo '<hr>';
| 关键词 | 类外声明 | 声明类 | 声明属性 | 声明方法 | 解释 |
|---|---|---|---|---|---|
| const | √ | √ | 定义类常量 | ||
| extends | √ | 扩展类,用一个类去扩展它的父类 | |||
| public | √ | √ | 公用属性或方法 | ||
| protected | √ | √ | 私有属性或方法 | ||
| private | √ | √ | 受保护的属性或方法 | ||
| abstract | √ | √ | 抽象类或方法 | ||
| final | √ | √ | 类不能被继承 |
static关键字定义self访问class People{ // 属性 public $name; // 属性 public $age; // 属性: 静态属性 public static $country = '中国'; // 构造方法 public function __construct($name, $age){ $this->name = $name; $this->age = $age; // $this->country = $country; // 会报错 // 尽管可以在构造方法中初始化静态属性,但不建议这样做,否则静态属性,无法在对象之间共享 } // 对象方法 public function getInfo1(){ // 这个方法可以用对象访问,方法中访问了静态属性,实现了类属性在对象中的共享 // return $this->name . '年龄是: ' . $this->age. '国家是:' . $this->country; // 这样会报错 return $this->name . '年龄是: ' . $this->age. '国家是:' . self::$country; } // 类方法: 静态方法 public static function getInfo2(){ // 静态方法是类方法, 不能用对象调用,所以内部也不允许使用对象引用$this // 如果静态方法中,一定要用到对象属性或方法,可以用参数传入 return $this->name . '年龄是: ' . $this->age . '国家是:' . self::$country; } // 静态方法: 以方法传参方式调用对象属性/方法 public static function getInfo3($name,$age){ // return $this->name; // 会报错,在静态方法里,不能访问非静态成员 // 可以用self调用,也可以用本类名调用。 最好在本类用self,在外部用类名 return $name . '年龄是: ' . $age . '国家是:' . Demo1::$country; } } $obj = new People('范冰冰',33); echo $obj->name, '<br>'; echo $obj->age, '<br>'; // echo $obj->country, '<br>'; //会报错 echo People::$country; // 应该以这种方式访问静态属性 echo '<br>'; echo $obj->getInfo1(), '<br>'; // echo $obj->getInfo2(), '<br>'; // 会报错 // echo People::getInfo2(), '<br>'; // 会报错 echo People::getInfo3($obj->name,$obj->age); echo '<br>'; // 对象不能访问静态属性,但是可以访问静态方法 echo $obj->getInfo3($obj->name,$obj->age); // 静态成员可以重新赋值。在创建很多对象,值不会因为创建的对象改变。 People::$country = 'china'; $obj1 = new People('杨幂',31); echo People::$country; echo '<hr>';
public是一样的define('COUNTRY','中国'); class People{ // 类常量也类属性一样,也是属于类的, 必须用类访问,不能用对象访问 const COUNTRY = '中国'; // 类常量与类属性的区别是: 类常量不允许修改,而类属性可以修改 public static $sex = '女'; private $name; public function __construct($name){ $this->name = $name; } public function getInfo(){ // 类常量在类的内部,访问方式与类属性是一样的 return $this->name.'的性别是:' . self::$sex.',国籍是: ' . self::COUNTRY; } } $obj = new People('刘诗诗'); // 访问类属性 echo People::$sex, '<br>'; // 访问类常量 echo People::COUNTRY, '<br>'; // 访问对象方法: 该方法又访问了类属性与类常量 echo $obj->getInfo(); echo '<hr>'; // 修改类属性 People::$sex = '保密'; // 修改类常量: 报错 //People::COUNTRY = '美国'; // 可以看到类属性:$sex发生了变化 echo $obj->getInfo(); echo '<hr>';
public__get($name): 当获取未定义可不见属性时触发,需要一个参数__set($name, $value) :当给未定义可不见属性赋值时触发,需要两个参数__isset($name): 当检测未定义可不见属性时触发__unset($name): 当注销未定义可不见属性时触发class People{ private $name; private $age; protected $country = '中国'; // public $country = '中国'; // 构造方法 public function __construct($name, $age){ $this->name = $name; $this->age = $age; } // __get($name):当获取未定义可不见属性时触发 // $name 是属性名 public function __get($name){ if ($name === 'country') { // 仅允许name=='admin'的用户可以查看country字段内容 return ($this->name === 'admin') ? $this->$name : '无权查看';; } return $this->$name; } // __set($name, $value):当给未定义可不见属性赋值时触发 public function __set($name, $value){ // 直接返回, 极少这样做,这样做相当于把类属性直接设置为:public // $this->$name = $value; // 添加过滤机制 if ($name === 'age') { return $this->name === 'admin' ? $this->$name = $value : '无权修改'; } return $this->$name = $value; } // __isset($name): 当检测未定义可不见属性时 public function __isset($name){ if ($this->name === 'admin') { if (isset($this->$name)){ echo '存在该属性'; } else { echo '没有该属性'; } } else { echo '无权检测'; } } //__unset($name): 当注销未定义可不见属性时触发 public function __unset($name){ if ($this->name === 'admin') { unset($this->$name); } else { echo '无法删除'; } } } $obj = new People('迪丽热巴', 26); echo $obj->name, '<br>'; echo $obj->country, '<br>'; // 怎么才能查看 country, 只能用'admin'来实例化 $obj = new People('admin', 50); echo $obj->country, '<br>'; // 直接修改 age, 类中没有__set()会报错 $obj->age = 80; // 查看age字段值 echo $obj->age, '<br>'; // 检测是否存在age字段 isset($obj->age); echo '<br>'; // 删除salary属性 unset($obj->age); echo '<br>'; isset($obj->age); echo '<hr>';
__call(): 访问未定义的对象方法时会自动调用它__callStatic(): 访问未定义的静态类方法时会自动调用它class People{ // __call(): 访问不存在/不可见对象方法时触发,有两个参数,第一个是方法名,第二个方法的参数 public function __call($name, $arguments){ return '方法名: '.$name.'<br>方法参数列表: ' . '<pre>'.print_r($arguments, true).'不存在'; } // __callStatic(): 访问不存在/不可见的类方法(静态)方法时触发 public static function __callStatic($name, $arguments){ return '方法名: '.$name.'<br>方法参数列表: ' . '<pre>'.print_r($arguments, true).'不存在'; } } $obj = new People(); // 访问不存在或无权访问的对象方法 echo $obj->getInfo1(10,20,30); echo '<hr>'; // 访问不存在或无权访问的静态类方法 echo Demo4::getInfo2('html','css', 'javascript'); echo '<hr>';
function sum($a, $b) { return $a . ' + ' . $b . ' = ' . ($a+$b); } // 正常函数调用 echo sum(20, 40); echo '<br>'; // 以回调的方式执行该函数 echo call_user_func('sum', 50, 20); echo '<br>'; // call_user_func_array(), 第二个参数是数组格式,不能省略 echo call_user_func_array('sum', [30, 80]); echo '<hr>';
// 现在换个思路, 将函数放在一个类中, 再来调用这个方法/函数 class Test1{ // 对象方法 public function sum($a, $b){ return $a . ' + ' . $b . ' = ' . ($a+$b); } } // 如果以回调方式执行对象方法呢? $obj = new Test1(); echo call_user_func([$obj,'sum'], 50, 20); echo '<br>'; // 仅以call_user_func_array()举例, call_user_func()原理一样 echo call_user_func_array([$obj,'sum'], [10,30]); echo '<br>'; // 如果仅调用一次,可以简化一下对象创建方式 echo call_user_func_array([new Test1(),'sum'], [15,35]); echo '<hr>';
// 如果是一个静态方法,如果调用呢? class Test2{ // 对象方法 (乘法运算) public static function mul($a, $b){ return $a . ' * ' . $b . ' = ' . ($a*$b); } } // 直接将类名与方法写在一个字符串即可 echo call_user_func_array('Test2::mul', [10,30]); echo '<br>'; // 将类名与类方法分开,放在一个数组中 echo call_user_func_array(['Test2','mul'], [10,30]); echo '<br>'; echo '类名是: '. Test2::class; // 返回一个类名字符串 echo '<br>'; // 所以这样写,也是正确的 echo call_user_func_array([Test2::class,'mul'], [10,30]);
下面是一个sql语句类的案例
require 'query.php'; class Db { // 数据库连接对象 protected static $pdo = null; // 数据库连接方法, 每次查询时再连接, 实现真正的惰性连接,节省系统开销 public static function connection(){ // 为简化,这里直接使用字面量参数连接数据库,真实项目中应该将参数放在配置文件中 self::$pdo = new PDO('mysql:host=localhost;dbname=ouyangke','root','root'); } // 这是查询类操作的入口, 通过静态魔术方法进行跳转,实现对象方法的跨类调用 public static function __callStatic($name, $arguments){ // 创建pdo对象,并连接数据库 self::connection(); // 实例化查询类,将连接对象做为参数 $query = new query(self::$pdo); // 执行查询类Query中的对象方法, 注意参数是数组,我只需要第一个参数:表名, 所以加了索引键名 return call_user_func_array([$query,$name],[$arguments[0]]); } } // 客户端的链式调用 // 以Db类做入整数数据库操作的入口, SQL语句的各个部分用对象方法提供 // 链式操作是现代PHP框架的基础,非常有用 $users = Db::table('user') ->field('uid,name,age') ->where('uid > 1') ->limit(5) ->select(); // 遍历查询结果 foreach ($users as $user) { print_r($user); echo '<br>'; }
query.php
<?php // 数据库查询类 class query { // 连接对象 public $pdo = null; // 数据表名 public $table = ''; // 字段列表 public $field = ''; // 查询条件 public $where = ''; // 显示数量 public $limit = 0; // 构造方法,初始化连接对象 public function __construct($pdo) { // 连接对象是对象方法的共享属性 $this->pdo = $pdo; } // 调用表名 public function table($tablName) { $this->table = $tablName; // 返回当前对象,便于链式调用该对象的其它方法 return $this; } // 设置查询字段 public function field($fields) { $this->field = $fields; return $this; } // 设置查询条件 public function where($where) { $this->where = $where; return $this; } // 设置显示数量 public function limit($limit) { $this->limit = $limit; return $this; } // 创建SQL查询语句对象,并返回查询结果 public function select() { // 查询条件分开设置, 可以确保链式方法独立 $fields = empty($this->field) ? '*' : $this->field; $where = empty($this->where) ? '' : ' WHERE '.$this->where; $limit = empty($this->limit) ? '' : ' LIMIT '.$this->limit; // 接装SQL语句 $sql = 'SELECT '.$fields.' FROM '.$this->table. $where . $limit; // 预处理查询 $stmt = $this->pdo->prepare($sql); $stmt->execute(); return $stmt->fetchAll(PDO::FETCH_ASSOC); } }
spl_autoload_register(callback): 通过回调自动加载外部文件__DIR__魔术常量// 查看当前脚本所在的目录 echo __DIR__, '<br>'; include __DIR__ . '/inc/Test1.php'; include __DIR__ . '/inc/Test2.php'; include __DIR__ . '/inc/Test3.php'; # 如果当前脚本使用了几十上百这样的类, 上面的方式就很不人性 # 使用下面的自动加载机制, 会根据客户端调用的类, 自动进行加载,效率高, 不出错
// php标准函数库中提供了一个自动加载文件的注册函数,可以实现这个功能 // 这个函数,在当前脚本引用一个未加载的文件时, 会自动调用它的回调方法来加载这个文件 spl_autoload_register(function ($class){ // include __DIR__ . '/inc/Test1.php'; // 将include中的类名Test1用变量替换掉,这样就实现了最简单的自动加载 // 后面我们会使用命名空间来完善这个函数,目前大家先理解到这里即可 include __DIR__ . '/inc/'.$class.'.php'; }); $test1 = new Test1(); echo $test1->get(), '<br>'; $test1 = new Test2(); echo $test1->get(), '<br>'; $test1 = new Test3(); echo $test1->get(), '<br>'; echo '<hr>';
abstract: 定义抽象方法/抽象类一个抽象类必须被扩展为一个特定的类,我们才能创建类实例,使用类中功能
abstract class a{ public $name; public function __construct($name){ $this->name = $name; } // 不管有多少个普通方法,只要有一个抽象方法,就是抽象类 public function af(){ echo $this->name; } // 抽象方法不能有内容,里面不能有代码,{}:不能有 abstract public function aff(); } // 抽象类不能实例化,不能new,只能继承 // 我们就用b类,继承 a抽象类 class b extends a{ // b类 继承 a抽象类后:必须把a抽象类 ,里面的抽象方法,重新写一遍(实现) public function aff(){ echo $this->name; } } // 实现后,我们可以调用子类,进行实例化,然后调用成员方法和成员变量。 $a = new b('欧阳克'); // 为什么抽象类里的af方法能调用呢,因为它是普通方法。 $a->af(); echo '<br/>'; // 这里的方法为什么能调用呢? 因为b类,继承了a抽象类的方法后:实现成为普通类。 $a->aff();
abstract class Person{ protected $name; protected function __construct($name='peter zhu'){ $this->name = $name; } // 该方法不需要重写, 可以通过子类对象访问,应该设置为public public function getName(){ return $this->name; } // 修改属性方法,设置为抽象方法,交给子类实现 abstract protected function setName($value); } // 当子类继承 抽象父类,普通的方法,可以直接使用,抽象方法,必须重新实现。 class Stu extends Person{ // 注意: 构造方法不会自动继承, 必须手动重写 public function __construct($name='peter zhu'){ parent::__construct($name); } // 1,它的父类,有这个抽象方法,这里必须重新写,带着具体的代码。 // 2,类实例化后,调用这个方法,就是直接调用这个方法,跟抽象方法没关系。 public function setName($value){ $this->name = $value; } } $stu = new Stu('猪哥'); echo 'php中文网创始人: ' . $stu->getName() . '<br>'; // 调用子类的重写的抽象方法setName(),来设置属性 $stu->setName('灭绝师太'); // 3,用setName传值后,值给到父抽象类里的$name,用父抽象类的getName方法可以输出传值 echo 'php中文网前端讲师: ' . $stu->getName() . '<br>'; echo '<hr>';
interface: 指定某个类必须实现的方法,但不需要定义方法的具体实现过程implements: 类实现接口的关键字interface iVehicle{ const COUNTRY = '中国'; // 驱动方式: 汽车, 新能源 public function setFuel($fuel); // 用途 public function setPurpose($purpose); } // Car 类 实现了接口: iVehicle,关键词:implements // 抽象类 实现接口: iVehicle,关键词:implements // 接口 可以 继承接口:extends // 类 可以 同时 继承 和实现(先继承,在实现) // 可以实现多个接口,用逗号隔开 class Car implements iVehicle{ public $fuel; public $purpose; // 构造方法 public function __construct($fuel='汽油', $purpose='家用'){ $this->fuel = $fuel; $this->purpose = $purpose; } // 必须实现的接口方法 public function setFuel($fuel){ $this->fuel = $fuel; } // 必须实现的接口方法 public function setPurpose($purpose){ $this->purpose = $purpose; } // 类中自定义的对象方法 public function getInfo(){ return $this->fuel . $this->purpose . '车 <br>'; } } // 客户端代码 $car = new Car(); echo $car->getInfo(); $car->setFuel('新能源'); $car->setPurpose('公交'); echo $car->getInfo(); echo '<hr>';
如果暂时只能实现接口中的部分方法, 可以用一个抽象来实现这个接口
interface iVehicle{ const COUNTRY = '中国'; // 驱动方式: 汽车, 新能源 public function setFuel($fuel); // 用途 public function setPurpose($purpose); } abstract class Auto implements iVehicle{ public $fuel; // 只实现接口中的setFuel()方法, 另一个方法并未实现 public function setFuel($fuel){ $this->fuel = $fuel; } } // 再创建一个类,来继承扩展这个抽象类 Auto class Car1 extends Auto{ public $purpose; // 构造方法 public function __construct($fuel='汽油', $purpose='家用'){ $this->fuel = $fuel; $this->purpose = $purpose; } // 这个方法原来在接口中声明的,在它继承的抽象类中并没有声明 public function setPurpose($purpose){ $this->purpose = $purpose; } // 自定义的方法 public function getInfo(){ return $this->fuel . $this->purpose . '车 <br>'; } } // 客户端代码 $car1 = new Car1(); echo $car1->getInfo(); $car1->setFuel('天然气'); $car1->setPurpose('家用'); echo $car1->getInfo();
// 定义一个接口,实现数据库常用操作:增删改查 interface iCurd { // 增加数据 public function create($data); // 读取数据 public function read(); // 更新数据 public function update($data, $where); // 删除数据 public function delete($where); } // 创建Db类, 实现iCurd接口,完成基本的数据库操作 class Db implements iCurd{ //数据库的连接对象 protected $pdo = null; // 数据表名 protected $table; // 构造方法: 连接数据库,并设置默认数据表名称 public function __construct($dsn, $user, $password, $table='staff'){ $this->pdo = new PDO($dsn, $user, $password); $this->table = $table; } // 读取 public function read($fields='*', $where='', $limit='0, 5'){ // 设置查询条件 $where = empty($where) ? '' : ' WHERE ' . $where; // 设置显示数量 $limit = ' LIMIT ' . $limit; // 预处理查询操作 $sql = 'SELECT '.$fields.' FROM '.$this->table.$where.$limit; $stmt = $this->pdo->prepare($sql); $stmt->execute(); // 返回二维数组表示的查询结果集 return $stmt->fetchAll(PDO::FETCH_ASSOC); } // 新增, 参数是数组: 新记录的键值对 public function create($data){ // 字段列表 $fields = ' (name,age,sex,position,mobile,hiredate)'; // 值列表 $values = '(:name,:age,:sex,:position,:mobile,:hiredate)'; // 创建SQL语句 $sql = 'INSERT INTO '.$this->table.$fields.' VALUES '.$values; // 预处理执行新增操作 $stmt = $this->pdo->prepare($sql); $stmt->execute($data); // 返回新增数量, 新增记录的ID组成的数组 return [ 'count'=>$stmt->rowCount(), 'id'=>$this->pdo->lastInsertId() ]; } // 更新, 为了数据安全, 不允许无条件更新 public function update($data, $where){ // 难点在于SET 参数的处理上,利用传入的$data数组,进行拆装 // 获取数组的键名组成的数组 $keyArr = array_keys($data); $set = ''; // 遍历键名表示的字段列表,拼装预处理需要的sql语句,注意占符符的表示 foreach ($keyArr as $value) { $set .= $value . ' = :' .$value. ', '; } // 去掉最后一个逗号, 注意每个逗号后有一个空格,去除时也要带上这个空格 $set = rtrim($set,', '); // 预处理执行更新操作 $sql = 'UPDATE '.$this->table.' SET '.$set .' WHERE ' .$where; $stmt = $this->pdo->prepare($sql); $stmt->execute($data); // 返回被更新的记录数量 return $stmt->rowCount(); } // 删除: 与更新一样, 这也是危险的写操作, 不允许无条件删除 public function delete($where){ // 预处理执行删除操作 $sql = 'DELETE FROM '.$this->table.' WHERE '.$where; $stmt = $this->pdo->prepare($sql); $stmt->execute(); return $stmt->rowCount(); } } // 客户端的测试代码 // 实例化Db类 $dsn = 'mysql:host=localhost;dbname=ouyangke'; $user = 'root'; $password = 'root'; $db = new Db($dsn, $user, $password); // 遍历读取 foreach ($db->read() as $item) { print_r($item); echo '<br>'; } echo '<hr>'; // 新增数据 $data = [ 'name'=>'郭靖', 'age'=>30, 'sex'=>1, 'position'=>'金刀驸马', 'mobile'=>'13666668888', 'hiredate'=>time() ]; $res = $db->create($data); echo '成功新增'.$res['count'].'条记录,最新记录的主键ID是: '.$res['id']; echo '<hr>'; // 更新记录 $data = [ 'age' => 5, 'position'=>'抗金英雄' ]; $where = 'id = 5'; echo '成功更新了: ' .$db->update($data, $where). ' 条记录'; echo '<hr>'; // 删除记录 $where = 'id = 5'; echo '成功更新了: ' .$db->delete($where). ' 条记录';
static 加上"范围解析符":::: 范围解析符的使用场景
class A{ public static function who(){ echo 111; } public function test(){ // self::who(); // 猜一下,是调用它自己的who,还是子类的who呢? // 那么如何在这种静态继承的上下文环境中, 静态调用类中方法的时候,正确识别调用者呢? // 可以将self 关键字改为: static , // 注意: static 除了可以用在静态方法中, 也可以用在普通对象方法中 static::who(); } } // B继承了A,重写A类里面的who方法。 class B extends A{ public static function who(){ echo 222; } } $a = new B(); echo $a->test();
[info] 表格表达类相关的关键词
| 关键词 | 类外声明 | 声明类 | 声明属性 | 声明方法 | 解释 |
|---|---|---|---|---|---|
| const | √ | √ | 定义类常量 | ||
| extends | √ | 扩展类,用一个类去扩展它的父类 | |||
| public | √ | √ | 公用属性或方法 | ||
| protected | √ | √ | 私有属性或方法 | ||
| private | √ | √ | 受保护的属性或方法 | ||
| abstract | √ | √ | 抽象类或方法 | ||
| final | √ | √ | 类不能被继承 | ||
| interface | √ | 创建接口 | |||
| implements | √ | 实现接口 | |||
| parent:: | 访问父类 | ||||
| $this-> | 访问本类 | ||||
| self:: | 访问静态 | ||||
| static:: | 后期静态绑定 | ||||
| namespace | √ | 创建命名空间 |