php面向对象基础详解【星际争霸游戏案例】
本文实例讲述了php面向对象基础。分享给大家供大家参考,具体如下:
前言
面向对象博大精深,对于从未接触过得的人,会觉得一头雾水。 学习的资料很多,但大多比较抽象,所以我用经典的游戏-星际争霸来讨论PHP面向对象。 现在假设我们来用PHP开发星际争霸,从而接触PHP面向对象。 注意,为了便于学习,除了特殊说明,否则各部分代码之间没有关联。而且同一件事情往往用的是不同的代码。 另外我也不去考证各个兵种的属性数字,仅仅用来说明。
一、类和对象
如果玩家制造了一个机枪兵,那么我们怎么表示他呢,因为每个机枪兵有几个基本的数据要记录:剩余的血,杀敌数量,攻击力等等。 我们可以用一个数组来记录一个机枪兵剩余的血和杀敌数量,因为这对于每个机枪兵是独立的。 但攻击力比较麻烦,因为经过升级,攻击力会增加,这就必须要找出所有表示机枪兵的数组,然后进行修改,非常麻烦。 从这里我们可以看出一件事情,首先每个机枪兵有独立的数据需要记录和修改,比如剩余的血。同时他们有相同的数据需要共用,比如攻击力。 这时候面向对象就能帮上我们的忙了。
1.1、类的定义
我们先来处理一部分问题,也就是每个机枪兵独有的数据。
<?php
class marine
{
public $blood = 50; //剩余的血
public $kills = 0; //杀敌数量
//这个函数(通常叫做方法)表示攻击敌人时候的运行代码
function attack($enemy)
{
//攻击敌人的代码
}
}
?
这叫做类,我们建立了一个表示所有机枪兵的类marine,这里面保留了需要每个兵独有的数据,比如上面代码里的剩余的血。
1.2、对象的创建和使用
接下来我们来使用对象,也就是每个机枪兵:
<?php
$m1 = new marine();
?
通过new后面加一个类的名字和括号,我们新建了一个机枪兵m1,m1被叫做类marine的对象,我们可以把它想象成一个特殊变量,只不过里面保存了多个数据。 如果需要使用或者操作某个机枪兵的血(对象的属性),只要用m1- blood来表示就可以了:echo m1- blood;//输出机枪兵
我们再建立一个机枪兵
<?php
$m2 = new marine();
?
如果此时m1被敌人攻击过了,还剩下10个血。而m2没受过攻击:
<?php
echo $m1- blood;//结果是10
echo $m2- blood;//结果是50
?
使用对象可以很简单的保存每个机枪兵的血,不会互相影响。 如果机枪兵$m1攻击敌人的时候,可以这样使用对象的方法:
<?php
$m1- attack($z1);//假设攻击的是某个小狗的对象$z1
?
不同的类内可以用同名的函数,比如小狗的类Zergling里面也可以有一个函数attack 要注意的是,从PHP5开始,无论在哪里改变一个对象的属性,都能改变它。比如上面一个小狗对象被作为参数传入机枪兵的attack函数,执行函数之后这个小狗对象的血减少了,这和一般的函数不同。但这是很直观的,如果一个小狗被攻击了,它的血就应该减少。
二、构造函数和析构函数
每次我们新建一个机枪兵的时候,总人口应该加1,如果一个机枪兵被杀,人口应该减少1。 可以通过构造函数和析构函数来自动处理:
<?php
class marine
{
//构造函数
function __construct()
{
//增加总人口的代码
}
//析构函数
function __destruct()
{
//减少总人口的代码
}
}
?
在一个类中,名字为__construct的函数叫做构造函数,每次new新建一个类的对象的时候就会执行:
<?php
$m1 = new marine();//每次制造一个机枪兵时系统会调用类marine的构造函数,自动增加总人口
?
在一个类中,名字为__destruct的函数叫做析构函数,每次销毁一个类的对象的时候就会执行:
<?php
unset($m1);//unset可以用于对象,表示销毁一个对象。每次一个机枪兵被杀时系统会调用类marine的析构函数,自动减少总人口
?
三、静态
机枪兵的攻击力是属于所有机枪兵对象,每个机枪兵的攻击力都是一样的,如果升级,应该一起变化。 这就用到static,表示静态:
<?php
class marine
{
static $attackNumber = 10; //攻击力的数字
//这个函数表示攻击敌人时候的运行代码
function attack($enemy)
{
//攻击敌人的代码,$enemy- blood表示敌人对象的血属性
$enemy- blood -= self::$attackNumber;
}
}
?
静态属性表示类所有的对象都共享的属性,一旦改变,所有的对象都跟着变化。 静态属性用static开头,比如上面的static $attackNumber。 静态属性可以用类直接访问:
<?php
echo marine::$attackNumber;//显示10
?
如果类以内的函数访问,用self::attackNumber表示本类的attackNumber属性 所以如果我们升级了机枪兵的攻击力,所有的机枪兵都受影响,这就是面向对象的好处之一,也解决了我们前面讨论的共同数据的问题。
函数也可以是静态的,这样就可以用类直接访问,不需要新建对象来调用:
<?php
class marine
{
static $attackNumber = 10; //攻击力的数字
//这个函数表示机枪兵升级的运行代码
staticfunction upgrade()
{
self::$attacknum++;
}
}
?
如果科技建筑升级完毕,直接就调用这个函数:
<?php
marine::upgrade();
?
四、继承
兵营用来造机枪兵,坦克房用来制造坦克,他们都是建筑,但是却有很多不同,如果用一个类“建筑”来表示,很困难。 但我们要保留他们的共性,比如都能飞行,不希望飞行的代码在各个类重复写,又要让他们能各自独立的生产不同的东西。 所以我们可以用继承来处理,继承表示父子关系,被继承的叫父类,继承的叫子类。用extends表示继承
<?php
//建筑类
class building
{
function fly()
{
//建筑飞行的代码
}
}
//兵营类
class marineBuilding extends building
{
function createMarine()
{
//制造机枪兵的代码
}
}
//坦克房类
class tankBuilding extends building
{
function createTank()
{
//制造坦克的代码
}
}
?
接下来,我们看看继承产生的效果:
<?php
//如果造了一个兵营:
$mb1 = new marineBuilding();
//一旦他需要飞行,就可以直接使用建筑类的函数fly(),尽管兵营类的定义里没有这个函数
$mb1- fly();
//而他要制造机枪兵的时候:
$mb1- createMarine();
?
同样是继承建筑类的坦克房类,就无法制造机枪兵,因为这是兵营类的个性。 如果在子类中的函数调用父类的函数,要使用parent,比如parent::fly() 注意,一个类只能有一个父类,PHP不允许多重继承,也就是说一个孩子只能有一个爹,一个爹可以有N个孩子!
五、访问控制
如果用attackNumber = 10表示属性的话,系统默认是public attackNumber = 10,所以建议这样写:
<?php
class marine
{
public static $attackNumber = 10; //攻击力的数字
}
?
public表示这个属性是公共的,也就是在任何地方都可以访问和操作的。
但这就存在一些问题,如果有玩家知道了类marine的一些代码结构,那他做个简单的补丁程序,运行的时候加载上去:
<?php
//补丁
marine::$attackNumber = 10000;
?
这样的话,他的机枪兵有10000的攻击力,呵呵,这样的话,谁打得过他!
为此我们要用private,表示这个属性只有类里面的函数才能访问:
<?php
class marine
{
private static $attackNumber = 10; //攻击力的数字
//这个函数表示机枪兵升级的运行代码
function upgrade()
{
//这样防止无限升级
if(self::$attacknum<13)
{
self::$attacknum++;
}
}
}
?
这样一来,只有升级才能改变机枪兵的攻击力。 但是现在往往是团队开发,而且很多用到类的继承,如果private的话,子类就无法访问了,但又不希望随便都可以修改某些属性。 那么可以用protected,protected的属性可以被子类的函数访问。
六、重载
6.1、属性重载
如果我们把地面部队作为一个类,让机枪兵类来继承他,这时候如果地面部队类和机枪兵类里面都定义了攻击力$attackNumber,那么每个兵的攻击力就决定于机枪兵类,而不是地面部队。这就叫做重载。
<?php
//地面部队
class groundArmy
{
public $attackNumber = 5;
}
//机枪兵
class marine extends groundArmy
{
public $attackNumber = 10; //攻击力的数字
}
$m1 = new marine();//新建一个机枪兵
echo $m1- attackNumber;//显示攻击力为10
?
6.2、函数重载
重载也可以用于函数,子类的函数如果和父类函数同名,除非另行说明,否则子类的对象默认调用子类内的函数。 比如人族的鬼兵类ghost和神族类的黑暗圣堂类(隐刀),都是隐形兵种,但是鬼兵隐形的时候会减少能量,黑暗圣堂根本没有能量属性。 如果我们把隐形能力作为父类,鬼兵类ghost和神族类的黑暗圣堂类DarkTemplar来继承它,同时实现不同的隐形代码:
<?php
//隐形能力类
class concealAbility
{
//这个函数表示隐形的运行代码
function conceal()
{
//隐形的运行代码
}
}
//鬼兵类
class ghost extends concealAbility
{
$energy = 150;
//这个函数表示隐形的运行代码
function conceal()
{
//隐形的运行代码
//减少鬼兵的能量,$this表示当前对象,也就是当前这个鬼兵
$this- energy -= 25;
}
}
//黑暗圣堂类
class DarkTemplar extends concealAbility
{
//这个函数表示隐形的运行代码
function conceal()
{
//隐形的运行代码,不影响能量
}
}
//新建一个鬼兵
$g1 = new ghost();
//显示能量为150
echo $g1- energy;
//鬼兵隐形
$g1- conceal();
//显示能量为125
echo $g1- energy;
//新建一个黑暗圣堂
$d1 = new DarkTemplar();
//黑暗圣堂隐形,他没有能量属性
$g1- conceal();
?
七、接口
PHP不允许多重继承,那么有些问题就难办了。 假如为了规范处理,我们把隐形的能力建立一个类,然后把飞行能力放一个类,那么人族的侦察机怎么处理?不能继承两个类! 那我们不用继承也行,但是开发组的其他人一旦涉及到侦察机,要把长长的代码读一遍吗?有没有可能知道类的所有方法的简要描述? 可以用到接口interface,一个类可以执行(继承)多个接口,接口中定义的函数不能有函数体,执行接口的类必须将这些函数完整定义。 这样我们知道侦察机实现了飞行能力接口,必然有接口里面描述的飞行方法://隐形能力的接口
<?php
interface concealAbility
{
public function conceal();
}
//飞行能力的接口
interface flyAbility
{
public function fly();
}
//侦察机类
class Wraith implements flyAbility, concealAbility
{
//这个函数表示侦察机飞行的运行代码
function fly()
{
//飞行的运行代码
}
//这个函数表示侦察机隐形的运行代码
function conceal()
{
//隐形的运行代码
}
}
?
八、总结
我们讨论了PHP面向对象的基本知识,通过星际争霸这一经典的游戏来说明,大家可以看到面向对象的初步作用。 我们看到通过面向对象可以使代码更加清晰,类将代码组织起来,比较方便的重复使用。 同时对象也减少了变量的冲突,方便相关性数据的保存和使用。 如果要解决的问题涉及很多方面,面向对象可以演化出更加灵活和有技巧的方式,比如通常提到的设计模式,和很多框架。 当然,面向对象也有缺点,从上面的代码可以看到,首先代码就多了,简单的任务如果定义许多类,反而麻烦。 对于简单任务,面向对象也可能使代码运行的效率降低。 深入的探讨,超出了本文的范围。
更多关于PHP相关内容感兴趣的读者可查看本站专题:《php面向对象程序设计入门教程》、《PHP数组(Array)操作技巧大全》、《PHP基本语法入门教程》、《PHP运算与运算符用法总结》、《php字符串(string)用法总结》、《php+mysql数据库操作入门教程》及《php常见数据库操作技巧汇总》
希望本文所述对大家PHP程序设计有所帮助。
- DoubleAnimation方法
- 已经重写,源码和文章请跳转http://www.cnblogs.com/ymnets/p/5621706.html
- 有趣 不用js也能创建silverlight
- Hadoop和Spark的异同
- ASP.NET MVC5+EF6+EasyUI 后台管理系统(62)-EF链接串加密
- sl 2.0 重要更新
- 云计算技术原理
- WCF技术剖析之五:利用ASP.NET兼容模式创建支持会话(Session)的WCF服务
- 进入AI时代,你准备好了吗?
- TiDB 在 G7 的实践和未来
- 投资钛值的你,知道钛链是什么吗?
- Is this a MS EnterLib DAAB BUG or not?
- Silverlight 2 has a Timer (DispatcherTimer)
- 难道调用ThreadPool.QueueUserWorkItem()的时候,真是必须调用Thread.Sleep(N)吗?
- php概述
- php教程
- php环境搭建
- PHP书写格式
- php变量
- php常量
- PHP注释
- php数组
- php字符串 string
- PHP整型 integer
- PHP浮点型 float
- php布尔型
- php数据类型之数组
- php数据类型之对象
- php数据类型之null
- php数据类型之间的转换
- php运算符
- php表达式
- PHP循环控制
- PHP流程控制
- php函数
- php全局变量
- PHP魔术变量
- php命名空间
- php 日期
- PHP包含文件
- php文件
- PHP 文件上传
- php Cookies
- php Sessions
- php email
- php安全email
- php错误处理
- PHP异常处理
- php过滤器
- PHP 高级过滤器
- php json
- php 表单
- PHP MySQL 简介
- PHP 连接 MySQL
- php创建数据库
- php 创建表
- php mysq 插入数据
- PHP MySQL 插入多条数据
- PHP MySQL 预处理语句
- php mysql 读取数据
- php mysql where
- PHP MySQL Order By
- PHP MySQL Update
- PHP MySQL Delete
- php ODBC
- 个人总结的部分数据验证规则
- 一句话实现php日期转中文汉字
- .Net Core微服务入门全纪录(八)——Docker Compose与容器网络
- PHP中少用但是很好用的方法
- 使用一维数据构造简单卷积神经网络
- .Net Core微服务入门全纪录(完结)——Ocelot与Swagger
- PHP使用GD库生成文件
- 反向传播算法从原理到实现
- 基于EntityFramework 6 Code First实现多租户的一种思路
- PHP使用GD库生成柱状图
- PHP生成Mysql数据字典
- .Net Core in Docker极简入门(上篇)
- PHP一个比较完善的树形结构代码
- .Net Core in Docker极简入门(下篇)
- snoopy(强大的PHP采集类) 详细介绍