- 2019-11-17
PHP基础加强系列六之OOP相关内容(一...
序言:本篇文章主要讲了PHP面向对象编程相关的知识,有点乱;
(1).类的自动加载
当要加载的类文件很多的时候可以使用;
例如一个初始化文件要引入很多类文件
现在有一个init.php要引入Dog.class.php,Cat.class.php,Pig.class.php.................
一般的情况是通过require来引入,像下面这样:
require './Dog.class.php'; require './Cat.class.php'; require './Pig.class.php'; .....
这样的坏处是不利于维护,如果引入的某些类文件并没有使用,就会造成浪费,所以现在引入__autoload
function __autoload($class_name){ require './'.$class_name.'.class.php'; }
只用一行代码就能实现类文件按需加载,前提是类文件和初始文件在同一个文件夹下,这样不利于扩展,如果我有另外的类文件放在不同的目录下,这个时候再这样写就不好了;所以可以通过建立数组映射,或者遍历文件目录来获取类文件,下面简单写个数组映射;
$class_map = [ 'Dog' => './upload/Dog.class.php', 'Cat' => './xx/Cat.class.php' ]; function __autoload($class_name){ global $class_map; require $class_map[$class_name]; }
Dog类存在于当前目录下的upload目录中,Cat类位于xx目录下,这样通过数组映射,就能实现对类文件的加载;当然使用遍历目录的方式可以更方便;还有一种更高级的类的自动加载,使用spl_autoload_register,通过回调的方式,来自动加载;
$class_map = [ 'Dog' => './upload/Dog.class.php', 'Cat' => './xx/Cat.class.php' ]; function MyAutoload($class_name){ global $class_map; require $class_map[$class_name]; } spl_autoload_register('MyAutoload'); $dog = new Dog(); echo $dog->talk(); $cat = new Cat(); echo $cat->talk();
这样输出也可以,通过spl_autoload_register,我们可以自定义函数来自动加载类文件;
(2).面向对象之静态变量
当有一个需求:例如有一个游戏,要求每加入一个人就记录一下,最后返回加入游戏的人数;如果不是oop很简单,但是如果是oop呢,同样简单;
这个时候就需要用到静态变量来记录人数;如果不声明静态变量,各个对象之间就不能共享这个游戏人数;举例子说明
class Game{ public $name = ''; public $child_count = 0; public function __construct($name) { $this->name = $name; } public function joinGame() { echo $this->name.'加入游戏
'; $this->child_count += 1; } public function personCount() { return '总计'.$this->child_count.'人加入游戏
'; } } $p1 = new Game('张飞'); $p2 = new Game('关羽'); $p1->joinGame(); $p2->joinGame(); echo $p1->personCount(); echo $p2->personCount();
使用这种普通变量来计数,每个对象的计数都是单独的;
输出:
张飞加入游戏
关羽加入游戏
总计1人加入游戏
总计1人加入游戏
现在做一下修改,将普通变量声明为静态:
class Game{ public $name = ''; public static $child_count = 0; public function __construct($name) { $this->name = $name; } public function joinGame() { echo $this->name.'加入游戏
'; self::$child_count++; } public function personCount() { return '总计'.self::$child_count.'人加入游戏
'; } }
输出:
张飞加入游戏
关羽加入游戏
总计2人加入游戏
总计2人加入游戏
因为在内存中的数据区静态变量和普通变量不一样,它会单独存在一个区域,而所有对象都指向这个静态数据区,如果是普通变量,同样一个数据区会存在两个普通变量,所以不一样;
注意细节:类中使用了关键字self,而不是$this,因为$this属于对象范畴,self属于类范畴,::表示范围解析符,->是对象运算符;类中public静态变量,在类外不用实例化就能调用,因为它属于类范畴,所以你可以这样用
class Dog{ public static $name = '小黑'; } echo Dog::$name;
输出:小黑,这里并没有实例化类Dog,但是可以通过类名::变量名来访问静态变量,即使你里面有构造函数,也一样
class Dog{ public static $name = '小黑'; function __construct() { echo '哈哈'; } } echo Dog::$name;
输出:小黑,因为构造函数是在实例化对象的时候才会触发;
如果你new了一个对象,就会触发
class Dog{ public static $name = '小黑'; function __construct() { echo '哈哈'; } } echo Dog::$name; $dog = new Dog();
输出:小黑哈哈
同理的还有静态方法,但是有一点需要注意就是静态方法中不能访问不同变量属性,这样会报错,因为静态方法是类相关,是抽象的,而普通变量是具体的,与对象相关,但是普通方法可以访问静态方法。
(3).PHP单利模式
在一次http请求中只能有一个对象实例,单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例。
final class Girl{ public $name; private static $instance = null; private function __construct($name) { $this->name = $name; } public static function getSingle($name){ //使用类型运算符判断是不是类本身 if(!(self::$instance instanceof self)) { self::$instance = new self($name); } return self::$instance; } private function __clone() {}
}
girl = Girl::getSingle('小白'); girl2 = Girl::getSingle(‘小红’);
echo girl->name; echo girl2->name;
var_dump(girl);
输出:
小白小白
F:\wamp64\www\test\test.php:1179:
object(Girl)[1]
public ‘name’ => string ‘小白’ (length=6)
F:\wamp64\www\test\test.php:1179:
object(Girl)[1]
public ‘name’ => string ‘小白’ (length=6)
//解释:构造函数和魔术方法__clone都变成私有的,私有构造函数是为了防止类外new一个对象,私有__clone是为了防止类外clone一个对象;final关键字是为了防止类被继承;
(4).对象运算符(->)的连用
例如:echo student->getSchool()->getClass()->name;
小例子:
class Student{ public name;
private school; function __construct(name)
{
this->name = name;
}
public function setSchool(value) { this->school = $value;
}public function getSchool()
{
return $this->school;
}
}class School{
public name; private school_class;
function __construct(name) { this->name = name; } public function setClass(value)
{
this->school_class = value;
}public function getClass()
{
return $this->school_class;
}
}class SchoolClass{
public name; private class_number;
function __construct(name) { this->name = $name;
}public function setNumber(value) { this->class_number = $value;
}public function getNumber()
{
return $this->class_number;
}
}class = new SchoolClass('网工二班'); class->setNumber(120);
school = new School('成都东软学院'); school->setClass(student = new Student('王二狗');
student->setSchool(school);echo student->getSchool()->getClass()->name;
输出:网工二班
//解释:有三个类,学生,学校,班级,通过学生能访问到学校和班级的信息;通过一个类能访问到其它类的信息就需要对象运算符;
另外的例子:通过一条狗找到狗主人,通过狗主人找到狗
class Dog{ public name;
private $master;function __construct(name) { this->name = $name;
}public function setMaster(value) { this->master = $value;
}public function getMaster()
{
return this->master; } } class Master{ public name;
private dog; function __construct(name)
{
this->name = name;
}
public function setDog(value) { this->dog = value; } public function getDog() { return this->dog;
}
}dog = new Dog('小黑'); master = new Master('王二狗');
dog->setMaster(master);
master->setDog(dog);echo ‘王二狗的宠物狗的名字:’.master->getDog()->name.'
'; echo '宠物狗小黑的主人:'.dog->getMaster()->name;
输出:
王二狗的宠物狗的名字:小黑
宠物狗小黑的主人:王二狗
转载请注明出处,谢谢!
- 上一篇: PHP基础加强系列五之魔术方法
- 下一篇: PHP基础加强系列七之OOP相关内容(二)
评论一下