PHP学习笔记(四)--面向对象
数据之道 2018-11-24 14:26:18 115 收藏 1
版权
注意事项:
1 无论是使用“$this->”还是使用“对象名->”格式,后面的变量是没有$符号的,如$this->value;
2 通过“类名::常量”方式类访问类常量的,如bastBall::Type;
3 在PHP中使用“垃圾回收”机制,不需要手动创建析构函数。不再使用的对象会自动清楚,释放内存;
4 对于成员方法,如果没有指定关键字,则默认是public,这一点与C++不同;
5 被protected修饰的类成员,可以在本类和子类中被调用,其它地方不可以,这也与C++不同;
6 在静态方法中,只能调用静态变量,而不能调用普通变量,而普通方法中可以调用静态变量;
7 在类内部访问静态成员使用“self::静态变量”,在类外部使用“类名::静态变量”;
8 构造函数__construct及析构函数__destruct不能声明为私有类型;
9 finale修饰的类不可被再继承,也不能再有子类。finale修饰的方法不可以进行重写,也不可以被覆盖;
10 抽象类是一种不能被实例化的类,只能作为其它的父类来使用。抽象类包含变量、成员方法,至少要包含一个抽象方法。抽象类和抽象方法主要用于复杂的层次关系中。
11 PHP只支持单继承,要想实现多继承就要使用接口。接口类中只能包含未实现的方法和一些成员变量。接口中的类成员必须使用public来修饰。接口类中的所有未实现的方法必须要在子类中实现;
12 类常量前面不加$符号。
【例1】类的定义及使用
<?php
class SportObject{
const TYPE='Sports';
static $counter=0;
private $name;
private $age;
private $sex;
public function __construct($name,$age,$sex){
$this->name=$name;
$this->age=$age;
$this->sex=$sex;
self::$counter++;//计数
}
public function __destruct(){
echo self::TYPE.'调用了析构函数';//类中访问常量使用self
}
public function PrintInfo(){
echo $this->name.',';
echo $this->age.',';
echo $this->sex.'<p>';
}
public function IsBoy(){
return $this->sex='男' ? true : false;
}
public function ShowCounter(){
echo '总共创建了:'.self::$counter.'个实例';
}
}
$so=new SportObject('张三',22,'男');
$so->PrintInfo();//调用成员方法
echo $so->IsBoy();
echo SportObject::TYPE;//访问类的常量
$sp2=new SportObject('张琴',25, '女');
$sp2->ShowCounter();
?>
【例2】继承
<?php
class SportObject{
protected $name;
private $age;
private $sex;
public function __construct($name,$age,$sex){
$this->name=$name;
$this->age=$age;
$this->sex=$sex;
self::$counter++;//计数
}
public function PrintInfo(){
echo '姓名'.$this->name.'<p>';
}
}
class BasketBallSports extends SportObject{
private $height;
public function __construct($name, $height){
$this->name=$name;
$this->height=$height;
}
public function PrintInfo(){//覆盖父类的方法
echo '身高:'.$this->height.'<p>';
}
}
$sp1=new BasketBallSports('郑钧', 188);
$sp1->PrintInfo();
?>
【例3】多态
<?php
class Overloader
{
private $properties = array();
function __get($property_name)
{
if(isset($this->properties[$property_name]))
{
return($this->properties[$property_name]);
}
else
{
return(NULL);
}
}
function __set($property_name, $value)
{
$this->properties[$property_name] = $value;
}
public function __call($method, $p)
{
if($method == 'display')
{
if(is_object($p[0]))
$this->displayObject($p[0]);
else
if(is_array($p[0]))
$this->displayArray($p[0]);
else
$this->displayScalar($p[0]);
}
}
public function displayObject($p)
{
echo ("你传入的是个对象,内容如下:<br>");
print_r($p);
echo "<hr>";
}
public function displayArray($p)
{
echo ("你传入的是个数组,内容如下:<br>");
print_r($p);
echo "<hr>";
}
public function displayScalar($p)
{
echo ("你传入的是个单独变量,内容如下:<br>" . $p);
echo "<hr>";
}
}
$o = new Overloader();
//调用 __set() 给一个不存在的属性变量赋值
$o->dynaProp = "Dynamic Content";
$o->display('Cat');
?>
【例4】抽象类
<?php
abstract class CommodityObject{
protected $type;
const CNAME='CommodityObject';
static public function Show(){
}
public function __construct(){
$this->type='通用类';
}
public function Display(){
echo $this->type;
}
abstract function service($getName,$price,$num);
}
class MyBooks extends CommodityObject{
function service($getName, $price, $num){
echo '书名:'.$getName.'<p>';
echo '价格:'.$price.'<p>';
echo '数量:'.$num.'<p>';
}
}
$book=new MyBooks();$book->service('PHP从入门到精通', 60, 3);
$book->Display();
?>
【例5】接口
<?php
interface MPopedom{
function popedom();
}
interface MPurview{
function purview($name);
}
class Manager implements MPopedom,MPurview{
function popedom(){
echo '拥有会员的权限';
}
function purview($name){
echo '拥有管理员的权限';
}
}
$manager=new Manager();
$manager->popedom();
$manager->purview('张三');
?>
使用close关键字进行对象的复制,直接将一个对象赋值给另一个对象$object2=$object1,则object2是object1的引用。有时候单纯的克隆对象外,还需要克隆出来的对象可以拥有自己的属性和方法,这时可以使用__clone()方法来实现,在对象的克隆过程中调用该方法。
<?php
class SpoerObject{
private $object_type='book';
public function setType($type){
$this->object_type=$type;
}
public function getType(){
return $this->object_type;
}
}
$book1=new SpoerObject();
$book2=$book1;
$book2->setType('computer');
echo $book1->getType();//输出computer
$book3=clone $book1;
$book3->setType('mouse');
echo $book1->getType();//还是输出computer
?>
<?php
class SpoerObject{
private $object_type='book';
public function setType($type){
$this->object_type=$type;
}
public function getType(){
return $this->object_type;
}
public function __clone(){
$this->object_type='computer';
}
}
$book1=new SpoerObject();
$book2=clone $book1;
echo $book2->getType();//输出computer
?>
使用“==”可以比较两个对象的内容是否相同,“===”可以比较两个对象的地址是否相同。
instanceof操作符可以检测当前对象是属于哪个类。一般格式为:
ObjectName instanceof ClassName
【例1】对象类型的比较
<?php
class SpoerObject{
private $object_type='book';
public function setType($type){
$this->object_type=$type;
}
public function getType(){
return $this->object_type;
}
}
$book1=new SpoerObject();
$book2=$book1;
$book3=clone $book1;
echo ($book2==$book1 ? "true" : "false").'<p>';//true
echo ($book2===$book1 ? "true" : "false").'<p>';//true
echo ($book3==$book1 ? "true" : "false").'<p>';//true
echo ($book3===$book1 ? "true" : "false").'<p>';//false
?>
【例2】
<?php
class SportObject{ }//创建空类
class BasketBallSports extends SportObject{
private $height;
public function __construct($height){
$this->height=$height;
}
public function PrintInfo(){//覆盖父类的方法
echo '身高:'.$this->height.'<p>';
}
}
$sp1=new BasketBallSports( 188);
echo ($sp1 instanceof BasketBallSports ? 'true' : 'false');//true
echo ($sp1 instanceof SportObject ? 'true' : 'false');//true
?>
PHP中以两个下划线“__”开头的方法,例如__destruct、__construct、__clone等都称为魔术方法。如果要调用这些魔术方法必须在类中进行定义。
13 __set()方法
当程序试图写入一个不存在或不可见的成员变量时,PHP会调用__set()方法。__set()包含两个参数,分别是变量名称和变量值,参数都不可省略。
14 __get()方法
当程序调用一个未定义或不可见的成员变量时,可以通过__get()方法来读取变量值。__get()犯法有一个参数,表示要调用的变量名。
【例1】
<?php
class SportObject{
private $type='';
public function __get($name){
if(isset($this->$name)){
echo "<p>变量".$name."的值为:".$this->$name;
}else{//如果变量未定义
echo "<p>变量".$name."未定义,初始化为0";
$this->$name=0;
}
}
public function __set($name,$value){
if(isset($this->$name)){
$this->$name=$value;
echo '<p>变量'.$name.'已定义';
}else{
echo '<p>变量'.$name.'未定义,被初始化为'.$value;
$this->$name;
}
}
}
$myComputer=new SportObject();
$myComputer->type='DIY';
echo $myComputer->type;
$myComputer->name;
?>
运行结果为:
15 __call()方法
当程序视图调用不存在或不可见的成员方法时,PHP会先调用__call()方法类存储方法名及其参数。__call()方法包含两个参数,即方法名和方法参数,其中方法参数是以数组的形式存在的。
<?php
class SportObject{
public function myDream(){
echo '不存在要 调用的方法时调用此方法<p>';
}
public function __call($method,$parameter){
echo '方法'.$method.'不存在';
echo '参数信息:';
var_dump($parameter);
$this->myDream();
}
}
$exam=new SportObject();
$exam->dream('张三',22);
?>
16 __sleep()方法和__wakeup()方法
PHP使用serialize()函数可以序列化对象。就是将类中的变量全部保存下来,对象中的类则只保存类名。当一个对象被串行化,PHP会调用__sleep方法(如果存在的话). 在反串行化一个对象后,PHP 会调用__wakeup方法. 这两个方法都不接受参数. __sleep方法必须返回一个数组,包含需要串行化的属性. PHP会抛弃其它属性的值. 如果没有__sleep方法,PHP将保存所有属性. 在程序执行前,serialize() 函数会首先检查是否存在一个魔术方法 __sleep.如果存在,__sleep()方法会先被调用,然后才执行串行化(序列化)操作。这个功能可以用于清理对象,并返回一个包含对象中所有变量名称的数组。如果该方法不返回任何内容,则NULL被序列化,导致一个E_NOTICE错误。与之相反,unserialize()会检查是否存在一个__wakeup方法。如果存在,则会先调用 __wakeup方法,预先准备对象数据。
<?php
class Connection {
protected $link;
private $server, $username, $password, $db;
public function __construct($server, $username, $password, $db)
{
$this->server = $server;
$this->username = $username;
$this->password = $password;
$this->db = $db;
$this->connect();
}
private function connect()
{
$this->link = mysql_connect($this->server, $this->username, $this->password);
mysql_select_db($this->db, $this->link);
echo '连接数据库成功!<p>';
}
public function __sleep()
{
return array('server', 'username', 'password', 'db');
}
public function __wakeup()
{
$this->connect();
}
}
$cnn = new Connection('localhost', 'root', null, 'students');
$str=serialize($cnn);
echo '序列化后的字符串'.$str.'<p>';
$recnn=unserialize($str);
?>
输出结果:
17 __toString()方法
当使用echo或print输出对象时,将对象转化为字符串。如果没有__toString()方法,直接输出对象会导致致命错误。注意,使用echo或print后面直接跟输出的对象,不可加入其它的字符。如echo ‘字符’.$myComputer不可以。
<?php
class Connection {
protected $link;
private $server, $username, $password, $db;
public function __construct($server, $username, $password, $db)
{
$this->server = $server;
$this->username = $username;
$this->password = $password;
$this->db = $db;
$this->connect();
}
private function connect()
{
$this->link = mysql_connect($this->server, $this->username, $this->password);
mysql_select_db($this->db, $this->link);
echo '连接数据库成功!<p>';
}
public function __toString(){
$res='服务器名:'.$this->server.'<p>';
$res.='用户名:'.$this->username.'<p>';
$res.='密码:'.$this->password.'<p>';
$res.='数据库:'.$this->db.'<p>';
return $res; }
}
$cnn = new Connection('localhost', 'root', '', 'students');
echo $cnn;
?>
18 __autoload()方法
__autoload()方法可以自动实例化所需要使用的类。__autoload()方法在指定的路劲下自动查找和该类同名称的文件,如果找到程序继续执行,否则报错。注意,类名必须与保存的文件名一致。
现在将上面5)中的类connection保存在当前工程目录下的connection.php中,index.php访问代码如下:
<?php
function __autoload($class_name){
$cname=getcwd().'\\'.$class_name.'.php';
if(file_exists($cname)){
include_once($cname);//动态引入类文件
}else{
echo '类路径'.$cname.'错误';
}
}
$cnn = new Connection('localhost', 'root', '', 'students');
echo $cnn;
?>