页面载入中...
首页 » Tag ‘游戏编程’

php绝对路径与相对路径之间关系的的深入研究

php中好像不能像asp那样用”/”表示根目录,代之以$_SERVER['DOCUMENT_ROOT'],其它则相同:../表示向上一层。./表示当前层。假如现在a/b/c/s.php要调用根目录下的 /bb/s2.txt,则:

$RootDir = $_SERVER['DOCUMENT_ROOT'];
$fireDir = “$RootDir/bb/s2.txt”;

或者:”../../../bb/s2.txt”表示向上返回到b再向上到a再向上到根目录然后到bb下。

前一阵子老是受php开发中,文件互相引入require()相对位置关系的困扰,为了彻底弄清它们的关系,笔者做了个实验。

以下是实验图:

当前项目(project2)的绝对路径是:D:\www\php_case\Coucom_make。也就是我们当前项目的根目录root.

为了能更加清楚的表述不同级别的目录文件相互的引入问题,偶大胆将引用分成三种类型即:上级对下级的引用(简称上级引用,英文译为:superior to underling。简称(stou)).

下级对上级的引用(简称下级引用,英文反之便是)

平级引用或叫同级引用(英文:paratactic)。  

好了,我们明确了引用类型,下面我们来看不同类型引用它们有着什么样的规则。

我们先来说说上级引用:

看我们的实验图,在图中项目下分别有aa bb ee 三个同级目录和一个index.php文件,在bb下又有cc目录,cc下又有dd目录和cc.php ccc.php两个文件,同样dd下也包含一个dd.php文件。凡是上层对下层均属上级引用.

例如:index.php对于所有文件的引用:
   cc .php对dd.php的引用:
   ee.php对dd.php的引用:

大家仔细看一下目录结构,便会发现这三种引用虽然同属于上级引用,但它们又不完全相同,我把它分成两种情况:即在上级引用中存在两种引用情况:1.从属的上级引用(类如cc.php对dd.php,,因为这两个文件同属于cc目录)2.非从属的上级引用(类如index.php对于所有文件的引用和 ee.php对dd.php的引用都属于这种情况因为它们与被引用的文件并没有一个共同的父目录,在能相对于站点根目录).

对于从属上级引用:

以下是在cc.php对dd.php的引用

require(‘dd/dd.php’);

对于非从属上级引用:

以下是在ee.php中对cc.php的引用

require(‘../bb/cc/cc.php’);

以上所说的是上级引用,下面我们来了解一下下级引用!同理下层对上层的引用都属于下级引用,同样分成从属与非从属两类,从属下级引用相对路径以它们的父目录为根目录,例如:

Ttt.php对bbff.php的引用就属于这种情况:require(‘../bb/cc/cc.php’);

非从属的下级引用却是以网站的根目录为准的,例如:

ccc.php对ee.php的引用: require(‘../../ee/ee.php’);

以上是下级引用的介绍,最后我们来看一下平级引用或者叫同级引用,其实同级引用也是分为这两种情况:从属同级引与非从属同级引用

从属同级引用很简单:即在同一个目录下的两个文件的引用

例如:在dd.php中引用ttt.php require(‘ttt.php’);

非从属同级引用:即不在同一个目录下(没有共同的父目录,只有以网站目站为父目录的情况),但是级别是相同的两个文件的引用,例如: 在aa.php在引用ee.php require(‘../ee/ee.php’);

以上是三种类型不同情况下的引用,另外还有涉及到嵌套引用的问题

比如:

ff.php引用dd.php,而dd.php又引用的gf.php,这种情况,本来dd.php 引用gf.php属于下级引用中的非从属引用,写法是这样的:require(‘../../../ee/gf.php’);而ff.php引用 dd.php属于上级引用中的从属引用,写法是这样的:require(‘./cc/dd/dd.php’); 可是你会发现在ff.php中无法找到 gf.php文件,那该如何写呢?我告诉你应该在dd.php中这样写:require(‘../ee/gf.php’);只有这样写就正确了,为什么呢?因为在涉及到嵌套引用的时候被引用文件的相对路径要以最终的引用文件为准!

简而言之:

其实很简单的,你用你的web根目录做根目录.不管你怎么定,你文件肯定有一个全部都要包含的文件的,比如有的较global.php,有的较common.php

假如这个文件放再根目录

wwwroot/global.php

里面第一行你加个chdir(dirname(__FILE__)); //切换到global.php所在目录就是跟目录

其他文件使用

require “../../../global.php”;
require “aa/aa.php”;
require “bb/bb/cc.php”;

这样就行了,因为你的global.php已经把路径切换到wwwroot了,你不用像很多人那么麻烦

define(‘ROOT_PATH’,dirname(__FILE__));
require ROOT_PATH…..

chdir(dirname(__FILE__)); 的确很好使,相对位置引入这个文件其他引入文件只要以他为基准就好了。

用PHP编程读取汉字点阵数据_PHP技巧

背景知识:  简体中文国标字库(1981年订,中国大陆)。7445个字符,其中汉字6773个,包括一级汉字3755个,二级汉字3008个。采用2字节(16位二进制)编码。   区位码:国标GB2312规定,所有的国标汉字与符号组成一个94×94的矩阵。在此方阵中,每一行称为一个”区”,每一列称为一个”位”,因此,这个方阵实际上组成了一个有94个区(区号分别为0 1到94)、每个区内有94个位(位号分别为01到94)的汉字字符集。一个汉字所在的区号和位号简单地组合在一起就构成了该汉字的”区位码”。在汉字的区位码中,高两位为区号,低两位为位号。由此可见,区位码与汉字或符号之间是一一对应的。  内码:汉字的内码是指在计算机中表示汉字的编码。机内码与区位码稍有区别。为什么不直接用区位码作为计算机内的编码呢? 这是因为汉字的区码和位码的范围都在1到94内, 如果直接用区位码作机内码, 就会与基本ASCII码冲突。 汉字的内码通常与所使用的计算机系统有关。目前,对于国内大多数的计算机系统,一个汉字的内码占两个字节,分别称为高位字节与低位字节,且这两位字节与区位码的关系如下: 内码高位=区码+A0H(H表示十六进制) 内码低位=位码+A0H 例如,汉字”啊”的区位码为”1601″,区码和位码分别用十六进制表示即为”1001H”,则它的内码为”B0A1H”。其中B0H为内码的高位字节,A1H为内码的低位字节。   php代码:返回由0和1组成的字符串。<?php/*** 读取汉字点阵数据** @author legend <legendsky@hotmail.com>* @link http://www.ugia.cn/?p=82* @Copyright www.ugia.cn*/$str = “中华人民共和国” ;$font_file_name = “simsun12.fon” ; // 点阵字库文件名$font_width = 12 ; // 单字宽度$font_height = 12 ; // 单字高度$start_offset = 0 ; // 偏移$fp = fopen ( $font_file_name , “rb” );$offset_size = $font_width * $font_height / 8 ;$string_size = $font_width * $font_height ;$dot_string = “” ;for ( $i = 0 ; $i < strlen ( $str ); $i ++){ if ( ord ( $str { $i }) > 160 ) {  // 先求区位码,然后再计算其在区位码二维表中的位置,进而得出此字符在文件中的偏移  $offset = (( ord ( $str { $i }) – 0xa1 ) * 94 + ord ( $str { $i + 1 }) – 0xa1 ) * $offset_size ;  $i ++; } else {  $offset = ( ord ( $str { $i }) + 156 – 1 ) * $offset_size ; } // 读取其点阵数据 fseek ( $fp , $start_offset + $offset , SEEK_SET ); $bindot = fread ( $fp , $offset_size ); for ( $j = 0 ; $j < $offset_size ; $j ++) {  // 将二进制点阵数据转化为字符串  $dot_string .= sprintf ( “%08b” , ord ( $bindot { $j })); }}fclose ( $fp );echo $dot_string ;?>   其中包括两个点阵字体文件:一个为16×16的chs16.fon,另一个为12×12的simsun12.fon,偏移均为零。

php计算24点游戏

求: 三个5,一个1组成的数学表达式的结果=24, 结果:(5-1/5)*5=24

<?php

set_time_limit(0);
$values = array(1, 5, 5, 5);
$result = 24;

$list = array();

echo “<pre>”;
makeValue($values);
print_r($list);

function makeValue($values, $set=array())
{
$words = array(“+”, “-”, “*”, “/”);
if(sizeof($values)==1)
{
$set[] = array_shift($values);
return makeSpecial($set);
}
foreach($values as $key=>$value)
{
$tmpValues = $values;
unset($tmpValues[$key]);
foreach($words as $word)
{
makeValue($tmpValues, array_merge($set, array($value, $word)));
}
}
}

function makeSpecial($set)
{
$size = sizeof($set);

if($size<=3 || !in_array(“/”, $set) && !in_array(“*”, $set))
{
return makeResult($set);
}

for($len=3; $len<$size-1; $len+=2)
{
for($start=0; $start<$size-1; $start+=2)
{
if(!($set[$start-1]==”*” || $set[$start-1]==”/” || $set[$start+$len]==”*” || $set[$start+$len]==”/”))
continue;
$subSet = array_slice($set, $start, $len);
if(!in_array(“+”, $subSet) && !in_array(“-”, $subSet))
continue;
$tmpSet = $set;
array_splice($tmpSet, $start, $len-1);
$tmpSet[$start] = “(“.implode(“”, $subSet).”)”;
makeSpecial($tmpSet);
}
}
}


function makeResult($set)
{
global $result, $list;
$str = implode(“”, $set);
@eval(“\$num=$str;”);
if($num==$result && !in_array($str, $list))
$list[] = $str;
}

?>

用星际争霸快速入门PHP面向对象编程

前言

面向对象 博大精深,对于从未接触过得的人,会觉得一头雾水。

学习 的资料很多,但大多比较抽象,所以我用经典的游戏-星际争霸来讨论 PHP 面向对象。

现在假设我们来用PHP开发星际争霸,从而接触PHP面向对象。

注意,为了便于学习,除了特殊说明,否则各部分 代码 之间没有关联。而且同一件事情往往用的是不同的代码。

另外我也不去考证各个兵种的属性数字,仅仅用来说明。

一、类和对象

如果玩家制造了一个机枪兵,那么我们怎么表示他呢,因为每个机枪兵有几个基本的数据要记录:剩余的血,杀敌数量,攻击力等等。

我们可以用一个数组来记录一个机枪兵剩余的血和杀敌数量,因为这对于每个机枪兵是独立的。

但攻击力比较麻烦,因为经过升级,攻击力会增加,这就必须要找出所有表示机枪兵的数组,然后进行修改,非常麻烦。

从这里我们可以看出一件事情,首先每个机枪兵有独立的数据需要记录和修改,比如剩余的血。同时他们有相同的数据需要共用,比如攻击力。

这时候面向对象就能帮上我们的忙了。

1.1、类的定义

我们先来处理一部分问题,也就是每个机枪兵独有的数据。

class marine

{

public $blood = 50; //剩余的血

public $kills = 0; //杀敌数量

//这个函数(通常叫做 方法 )表示攻击敌人时候的运行代码
function attack($enemy)

{

//攻击敌人的代码

}

}

这叫做类,我们建立了一个表示所有机枪兵的类marine,这里面保留了需要每个兵独有的数据,比如上面代码里的剩余的血。

1.2、对象的创建和使用

接下来我们来使用对象,也就是每个机枪兵:

$m1 = new marine();

通过new后面加一个类的名字和括号,我们新建了一个机枪兵$m1,$m1被叫做类marine的对象,我们可以把它想象成一个特殊变量,只不过里面保存了多个数据。

如果需要使用或者操作某个机枪兵的血(对象的属性),只要用$m1->blood来表示就可以了:

echo $m1->blood;//输出机枪兵$m1剩余的血

我们再建立一个机枪兵

$m2 = new marine();

如果此时$m1被敌人攻击过了,还剩下10个血。而$m2没受过攻击:

echo $m1->blood;//结果是10

echo $m2->blood;//结果是50

使用对象可以很简单的保存每个机枪兵的血,不会互相影响。

如果机枪兵$m1攻击敌人的时候,可以这样使用对象的方法:

$m1->attack($z1);//假设攻击的是某个小狗的对象$z1

不同的类内可以用同名的函数,比如小狗的类Zergling里面也可以有一个函数attack

要注意的是,从PHP5开始,无论在哪里改变一个对象的属性,都能改变它。比如上面一个小狗对象被作为参数传入机枪兵的attack函数,执行函数之后这个小狗对象的血减少了,这和一般的函数不同。但这是很直观的,如果一个小狗被攻击了,它的血就应该减少。

二、构造函数和析构函数

每次我们新建一个机枪兵的时候,总人口应该加1,如果一个机枪兵被杀,人口应该减少1。

可以通过构造函数和析构函数来自动处理:

class marine

{

//构造函数
function __construct()

{

//增加总人口的代码

}

//析构函数
function __destruct()

{

//减少总人口的代码

}

}

在一个类中,名字为__construct的函数叫做构造函数,每次new新建一个类的对象的时候就会执行:

$m1 = new marine();//每次制造一个机枪兵时系统会调用类marine的构造函数,自动增加总人口

在一个类中,名字为__destruct的函数叫做析构函数,每次销毁一个类的对象的时候就会执行:

unset($m1);//unset可以用于对象,表示销毁一个对象。每次一个机枪兵被杀时系统会调用类marine的析构函数,自动减少总人口

三、静态

机枪兵的攻击力是属于所有机枪兵对象,每个机枪兵的攻击力都是一样的,如果升级,应该一起变化。

这就用到static,表示静态:

class marine

{

static $attackNumber = 10; //攻击力的数字

//这个函数表示攻击敌人时候的运行代码
function attack($enemy)

{

//攻击敌人的代码,$enemy->blood表示敌人对象的血属性

$enemy->blood -= self::$attackNumber;

}

}

静态属性表示类所有的对象都共享的属性,一旦改变,所有的对象都跟着变化。

静态属性用static开头,比如上面的static $attackNumber。

静态属性可以用类直接访问:

echo marine::$attackNumber;//显示10

如果类以内的函数访问,用self::$attackNumber表示本类的$attackNumber属性

所以如果我们升级了机枪兵的攻击力,所有的机枪兵都受影响,这就是面向对象的好处之一,也解决了我们前面讨论的共同数据的问题。

函数也可以是静态的,这样就可以用类直接访问,不需要新建对象来调用:

class marine

{

static $attackNumber = 10; //攻击力的数字

//这个函数表示机枪兵升级的运行代码
static function upgrade()

{

self::$attacknum++;

}

}

如果科技建筑升级完毕,直接就调用这个函数:

marine::upgrade();

四、继承

兵营用来造机枪兵,坦克房用来制造坦克,他们都是建筑,但是却有很多不同,如果用一个类”建筑”来表示,很困难。

但我们要保留他们的共性,比如都能飞行,不希望飞行的代码在各个类重复写,又要让他们能各自独立的生产不同的东西。

所以我们可以用继承来处理,继承表示父子关系,被继承的叫父类,继承的叫子类。用extends表示继承

//建筑类

class building

{

function fly()

{

//建筑飞行的代码

}

}

//兵营类

class marineBuilding extends building

{

function createMarine()

{

//制造机枪兵的代码

}

}

//坦克房类

class tankBuilding extends building

{

function createTank()

{

//制造坦克的代码

}

}

接下来,我们看看继承产生的效果:

//如果造了一个兵营:

$mb1 = new marineBuilding();

$mb1->fly();

//而他要制造机枪兵的时候:

$mb1->createMarine();

同样是继承建筑类的坦克房类,就无法制造机枪兵,因为这是兵营类的个性。

如果在子类中的函数调用父类的函数,要使用parent,比如parent::fly()

注意,一个类只能有一个父类,PHP不允许多重继承,也就是说一个孩子只能有一个爹,一个爹可以有N个孩子!

五、访问控制

如果用$attackNumber = 10表示属性的话,系统默认是public $attackNumber = 10,所以建议这样写:

class marine

{

public static $attackNumber = 10; //攻击力的数字

}

public表示这个属性是公共的,也就是在任何地方都可以访问和操作的。

但这就存在一些问题,如果有玩家知道了类marine的一些代码结构,那他做个简单的补丁程序,运行的时候加载上去:

//补丁

marine::$attackNumber = 10000;

这样的话,他的机枪兵有10000的攻击力,呵呵,这样的话,谁打得过他!

为此我们要用private,表示这个属性只有类里面的函数才能访问:

class marine

{

private static $attackNumber = 10; //攻击力的数字

//这个函数表示机枪兵升级的运行代码
function upgrade()

{

//这样防止无限升级

if(self::$attacknum<13)

{

self::$attacknum++;

}

}

}

这样一来,只有升级才能改变机枪兵的攻击力。

但是现在往往是团队开发,而且很多用到类的继承,如果private的话,子类就无法访问了,但又不希望随便都可以修改某些属性。

那么可以用protected,protected的属性可以被子类的函数访问。

六、重载

6.1、属性重载

如果我们把地面部队作为一个类,让机枪兵类来继承他,这时候如果地面部队类和机枪兵类里面都定义了攻击力$attackNumber,那么每个兵的攻击力就决定于机枪兵类,而不是地面部队。这就叫做重载。

//地面部队

class groundArmy

{

public $attackNumber = 5;

}

//机枪兵

class marine extends groundArmy

{

public $attackNumber = 10; //攻击力的数字

}

$m1 = new marine();//新建一个机枪兵

echo $m1->attackNumber;//显示攻击力为10

6.2、函数重载

重载也可以用于函数,子类的函数如果和父类函数同名,除非另行说明,否则子类的对象默认调用子类内的函数。

比如人族的鬼兵类ghost和神族类的黑暗圣堂类(隐刀),都是隐形兵种,但是鬼兵隐形的时候会减少能量,黑暗圣堂根本没有能量属性。

如果我们把隐形能力作为父类,鬼兵类ghost和神族类的黑暗圣堂类DarkTemplar来继承它,同时实现不同的隐形代码:

//隐形能力类

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 ,一个类可以执行(继承)多个接口,接口中定义的函数不能有函数体,执行接口的类必须将这些函数完整定义。

这样我们知道侦察机实现了飞行能力接口,必然有接口里面描述的飞行方法:

//隐形能力的接口

interface concealAbility

{

public function conceal();

}

//飞行能力的接口

interface flyAbility

{

public function fly();

}

//侦察机类

class Wraith implements flyAbility, concealAbility

{

//这个函数表示侦察机飞行的运行代码
function fly()

{

//飞行的运行代码

}

//这个函数表示侦察机隐形的运行代码
function conceal()

{

//隐形的运行代码

}

}

八、总结

我们讨论了PHP面向对象的基本知识,通过星际争霸这一经典的游戏来说明,大家可以看到面向对象的初步作用。

我们看到通过面向对象可以使代码更加清晰,类将代码组织起来,比较方便的重复使用。

同时对象也减少了变量的冲突,方便相关性数据的保存和使用。

如果要解决的问题涉及很多方面,面向对象可以演化出更加灵活和有技巧的方式,比如通常提到的 设计模式 ,和很多 框架

当然,面向对象也有缺点,从上面的代码可以看到,首先代码就多了,简单的任务如果定义许多类,反而麻烦。

对于简单任务,面向对象也可能使代码运行的效率降低。

深入的探讨,超出了本文的范围。