1结构和调用(实例化)php
class classname{},调用$obj = new classname();当类有构造函数时,应传入参数数组
如$obj = new classname($v1,$v2...);函数
2构造函数和析构函数学习
一、构造函数用于初始化:使用__construct()可带参数ui
二、析构函数不能带参数。使用_destruct()。在脚本执行结束时,会销掉内存中的对象,所以可不用析构函数。但有些好比COOKIE等,就应该用析构函数销毁。this
在php 4.0以前使用类名做为析构函数名。php5中还可使用。当不包含__construct()时,会查找与类名相同的方法。默认为构造函数。spa
class test
{ var $b;
function test() { $this->b=5; }
function addab($c) { return $this->b+$c; }
}
$a = new test(); echo $a->addab(4); // 返回 9code
三、PHP不会自动调用父类的构造函数(不支持构造函数重载),必须使用parent关键字显式调用对象
class employee{
function __construct()….
}
class Manager extents Employee{
function __construct(){
parent::_construct();
echo ‘这个子类的父类构造函数调用了!';
}
}继承
类的属性
有两种方法对类的属性赋值或取值
1.使用公共做用域public关键词。
2.使用__set()和__get()来分别复制和取值。(优势:统一进行数据验证;便于统一管理属性;)
__set()和__get()只对私有属性起做用。对public定义的属性不起做用。
class test{
protected $a=9,$b=2,$c;
public $d;
function __set($n,$v) { $this->$n = $v+2; }
function __get($name) { return $this->$name+2; }
}
$a = new test();
$a->b =5; echo “<br />”; echo $a->b;
_set($n,$v)要带两个参数。而__get($n)只能有一个参数。实例:
class test{
private $a=5,$b=6,$c;
function __set($n,$v)
{
if($n=='a'&&$n>0)
$this->$n = $v;
else
$this->$n = $v+2;
}
function __get($name)
{
return $this->$name; //若是改成return $this->$name + $this->addab(); 如调用a的值,实际返回的是a+a+b的值。默认为5+5+6=16。
}
function addab()
{ return $this->a + $this->b; }
}
$e=new test();
$e->a = 11; //注意写法:类的内部用$this->$n即变量的写法,但外部实例要用$e->a的方式。
$e->b = 12; //get 14
$e->k = 22;
类的属性可自由扩展,如上例的k,不论是否用__set,当一个实例创建起来后,能够用$e->newProperty = xx;直接来创造一个属性,但不建议这么作。
类的方法(函数)
调用
内部调用:shiyong$this->fanname()或者$this->addab()或者test::addab()
实例化调用使用$this->addab();对于在该方法中没有使用$this关键字的,如上例中的:
function addab() { return $this->a+$this->b; }
改成: function addab() { return 25; }那在在外部实例调用该方法,也可用“$e::addab();”或“test::addab();”
类的常量
class test{
private $a;
const PI = '3.14′;
…..
//在类中调用上面的常量用两种方法,“$this::PI”,或 “类名::PI”,这里就是test::PI,以下:
function getvalue(){
return $this->a * $this::PI; //或$this->a * test::PI,用this关键字或类名都可,但都要用双冒号。
}
}
$e= new test();
$e->PI =5; //注意,这里用 ->只是创造了一个也是名为PI的属性,而不是改变类中的PI常量的值。
6、类的静态成员(静态属性或静态方法):
若是须要建立供全部类的实例共享的字段或方法。就得用静态成员。有两个特征:
一、静态成员是共产主义者,它让脚本上的全部该类的实例调用,但不能借助类的特定实例名调用,而是在类的外部,统一使用“类名::$成员名”的方式调用。而类的内部则统一使用 “self::$成员名”来调用。
二、当每一次新建立实例时,静态成员会从上次建立的实例最后值开始从新计算,而不是类中初始的值开始计算。
三、对于用public定义的静态成员,能够在外部更改它的值。private等则不行。
class test{
public static $v = 0;
function __construct(){ self::$v++; }
static function getV(){ return self::$v; }
}
$a = new test();
echo test::getV(); // 返回 1
$b = new test();
echo test::getV(); // 返回 2
test::$v=8; //因为public定义的成员,改变静态成员的值。
$c = new test();
echo test::getV(); // 返回 9
echo $e::PI; //这个才是调用类的常量。
常量只能用双冒号::来调用,而且不能更改其值
在类外部实例化后调用类常量一样也有两种方法。
$e::pi或者test::pi外部不能使用this 只能使用实例名。但classname::pi是通用的。
关键字:
(一)this关键字:用于类的内部指代类的自己。来访问属性或方法或常量,如$this->属性名或方法名。$this::常量名。this还能够用在该类的子类中,来指代自己的属性或方法。
(二)双冒号“::”关键字:用于调用常量、静态成员。
(三)self关键字:在类的内部与双冒号配合调用静态成员,如 self::$staticVar.,在类的内部,不能用$this来调用静态成员。
(四)__toString():在类中使用__toString(),用于将类转成字串并打印类,用处不大:如:
class test{ public $p;
public function __toString(){ return var_export($this,TRUE); }
}
$a=new test();
echo $a; //输出:test::__set_state(array( ‘p' => NULL, )),或写成:echo $a->__toString();
(五)__clone() :当克隆对象时,这个关键字才会发生做用,用于更改克隆时某些值。
(六)__call():方法重载,参下面示例:
class cB{
function __call($method,$n){
if($method=='showVarType'){
if(is_numeric($n[0])){ //不能用$n。要用$n[0];
$this->displayNum();
}else if (is_array($n[0])){
$this->displayArr();
}else{
$this->displayOther();
}
}
}
function displayNum() {
echo ‘<h3>这是数字!</h3>';
}
function displayArr() {
echo ‘<h3>这是数组!</h3>';
}
function displayOther() {
echo ‘<h3>不是数组也不是数字!</h3>';
}
}
$x='a';
$y=array(‘a','b');
$b=new cB;
$b->showVarType($x); //不是数组也不是数字
$b->showVarType($y); //这是数组
(七)extends:继承: 如class a{} class b extends a{} 类b继承了类a
记忆:之后统一在调用方法或属性时用 “-> “,调用常量则用双冒号“::”,不会搞晕。
方法和属性的做用域:
共有6种:public(默认,可省略,也等同于php6的var声明),private(私有,也不能由子类使用),protected(私有,但可由子类使用) ,abstract(抽象,参下文),final(阻止在子类中覆盖—也称重载,阻止被继承,用于修饰类名及方法,如final class test{ final function fun(){}} ,但不能用于属性),static(静态)
抽象类和抽象方法(abstract——注意:没有所谓抽象属性):
抽象能够理解成父类为子类定义了一个模板或基类。做用域abstract只在父类中声明,但在子类中实现。注意事项:
一、抽象类不能被实例化,只能被子类(具体类)继承后实现。
二、抽象类必须在其子类中实现该抽象类的全部抽象方法。不然会出错。
三、在抽象方法中,只是声明,但不能具体实现:如abstract function gettow(){ return $this->p; }是错的,只能声明这个方法:abstract function gettow();(连方括号{}都不要出现),抽象方法和抽象类主要用于复杂的类层次关系中。该层次关系须要确保每个子类都包含并重载了某些特定的方法。这也能够经过接口实现
四、属性不能被命名为抽象属性,如abstract $p = 5是错的。
五、只有声明为抽象的类能够声明抽象方法,但若是方法声明为抽象,就不能具体实现。如:
abstract class Employee
{
abstract function a(…);
abstract function b(…);
}
之后再对这个父类扩展,组成各类子类(如经理,员工,出纳)。
6.抽象类中,若是要实现具体的方法,不能声明为抽象。这样可能实际意义更大。能够把几个类库中共同的部分提取到抽象类中,其它的类继承抽象类便可。以下:
abstract class BaseShop{
Const TAX=0.06; // 在抽象类中定义常量
public function buy($gid) { // 若是定义为抽象方法abstract function buy()就不能在这里实现主体。
echo(‘你购买了ID为 :'.$gid.'的商品');
}
public function sell($gid) {
echo(‘你卖了ID为 :'.$gid.'的商品');
}
public function view($gid) {
echo(‘你查看了ID为 :'.$gid.'的商品');
}
}
class BallShop extends BaseShop{
var $itme_id = null;
public function __construct()
{
$this->itme_id = 2314;
}
public function open()
{
$this->sell($this->itme_id);
}
public function getTax()
{
echo printf(‘<h3>平均税率是 %d%%。</h3>',$this::TAX*100);
}
}
$s = new BallShop;
$s->open(); //你卖了ID为 :2314的商品
$shop->getTax();
类型提示:
注意,类型提示功能只能用于参数为对象的提示,而没法用于为整数,字串,浮点等类型提示。有些类的方法须要传入的参数为所指望的对象类型,能够用下面的方法达到强制实施此替则。要达到类型提示,只要在方法的对象型参数前加一个已存在的类的名称,如:function funname(OtherClassName $otherclassINSName,$c….),注意,OtherClassName必须是存在的类。
11、类的管理:
一、instanceof关键字:用于分析一个对象是不是某一个类的实例或子类或是实现了某个特定的接口:以下例,但要注意: 类名没有任何引号等定界符,不然会出错。如test不能用'test'
class test2{}
class test{}
class testChilern Extends test{}
$a = new test2();
$m = new test();
$i = ($m instanceof test);
if($i)echo ‘$m是类test的实例!<br />'; // get this value
switch ($a instanceof test){
case true :
echo ‘YES<br />';
break;
case false :
echo ‘No<br />'; //get this value
break;
}
$d=new testChilern();
if($d instanceof test)echo ‘$d是类test的子类!<br />'; // get this value
二、肯定类是否存在:boolean class_exists(string class_name): class_exists(‘test');
三、返回类名:string get_class(object),成功时返回实例的类名,失败则返回FALSE:
$a = new test2(); echo get_class($a); //返回 test2
四、了解类的公用属性:array get_class_vars(‘className') ,返回关键数组:包含全部定义的public属性名及其相应的值。这个函数不能用实例名作变量
五、返回类方法:get_class_methods(‘test'); //或: get_class_methods($a);可用实例名作参数,返回包括构造函数在内的全部非私有方法。
六、print_r(get_declared_classes())了解当前PHP版本中全部的类名。PHP5有149个。
七、get_object_vars($a)返回实例中全部公用的属性及其值的关联数组。注意它和get_class_vars()的区别:
/* (1) get_object_vars($a)是用实例名作参数,而get_class_vars(‘test')是用类名作参数。
* (2) get_object_vars($a)得到的属性值是实例运行后的值,而get_class_vars(‘test')得到的属性值是类中的初始定义。
* (3) 二者均返回关联数组,且均对未赋值的属性返回NULL的值。如类test中有定义了public $q;则返回Array ( [v] => 5 [q]=>) ,
*/
八、返回父类的名称:get_parent_class($b);//或get_parent_class(‘test2′); 返回test
九、肯定接口是否存在:boolean interface_exists($string interface[,boolean autoload])
十、肯定对象类型: boolean is_a($obj,'className'),当$obj属于CLASSNAME类时,或属于其子类时,返回TRUE,若是$obj与class类型无关则返回FALSE。如:is_a($a,'test')
十一、肯定是不是某类的子对象:当$b是继承自TEST类时,返回TRUE,不然FALSE。boolean is_subclass_of($b,'test');
十二、肯定类或实例中,是否存在某方法。method_exists($a,'getv') //或用method_exists(‘test','getv'),此函数适用于非public定义的做用域的方法。
class test{
public $v=2;
private $c=5;
function __construct(){
$this->v=5;
}
private function getv(){
return $this->v;
}
}
class test2 extends test{}
$a=new test();
$b=new test2();
print_r( get_class_methods(‘test')); //或:print_r( get_class_methods($a)); 均返回:Array ( [0] => __construct [1] => getv )
echo ‘<br />';
print_r( get_class_vars(‘test')); //返回:Array ( [v] => 2 ),和上面不同,不能用print_r( get_class_methods($a));
echo ‘<br />';
echo get_parent_class($b);//或get_parent_class(‘test2′); 返回test
echo ‘<br />';
echo is_a($b,'test');// 返回1
echo ‘<br />';
if(is_subclass_of(‘test2′,'test'))echo ‘是子类!'; //或(is_subclass_of($b,'test')),返回1,当参数1为$a时则返回false,
echo ‘<br />';
echo method_exists($a,'getv') //或用method_exists(‘test','getv')返回1,本函数也适用于用private等定义域的方法。
11、自动加载类库文件:
当类多了之后,好比要在一个文件中载入3个类库文件:a.class.php,b.class.php,c.class.php要用三个require_once(‘classes/a.class.php);
require_once(‘classes/b.class.php);
require_once(‘classes/c.class.php);
能够用PHP5自动加载的功能来处理:在全局应用配置文件中,定义一个特殊的函数__autoload($class)函数(__autoload并非一个类的方法,只是单独的函数,和类没有关系):
function __autoload($class){
require_once(“classes/$class)
}
该函数放哪没有关系,在建立类实例时,也没必要去调用这个autoload函数。PHP会自动完成。但务必注意一点:“在调用页面上建立实例所使用的类名称”、和“被调用的文件名”、以及“该文件中的类的名称”3个必须是同样的。这样就不须要去调用__autoload();若是不同则必须单独调用__autoload(‘c');并给它一个文件名前缀。如:
1、对象克隆:
当克隆一个对象的实例时,其属性初始值继承了被克隆对象的当前值。
2、对象继承:
没有被声明为final的类能够被继承,没有被final和private界定的方法也能够继承,没有被private界定的属性也能够继承。当子类继承了父类或超类后,能够直接使用父类或超类(祖父类以及祖父的祖父)的全部容许的方法,属性。
关键:理解构造函数和重载在继承中的特性!
(一)构造函数在继承中的特性:
一、当父类有构造函数而子类没有:则子类会在实例化时会自动执行父类的构造函数。这时若是要建立子类的实例,须要引入父类构造函数中所需的参数,不然出错。即便是“子类的子类”若是没有构造函数,也要在建立实例时输入其父类的父类的构造函数所需参数。PHP会从实例所在的子类会向上搜索合造的构造函数,一旦找到就中止,使用该构造函数。而不会再向上搜索,所以:子类自己若是没有构造函数,则以其最靠近的一个超类而且有构造函数的为准。
class cB extends cA{
function funB1() { echo ‘<h3>Class cB execute success!</h3>'; }
}
class cC extends cB {
function funC1() { echo ‘<h3>Class cC FunC1!</h3>'; }
}
$b=new cB(‘Jack');
$b->name='John';
echo “$b->name : $b->age”;
$b->funB1();
$c=new cC(); //这里会出错,因为cB也没有构造函数,所以再向上以cA为准,须要一个参数。改成$c=new cC(‘David');便可。
echo $c->name(); //David
二、当子类也有构造函数时:这时,无论父类是否有构造函数,都会执行子类本身的构造函数。
如上:
如今类CB有本身的构造函数时,这时建立实例$b=new cB(‘Jack');参数JACK不会起做用,由于父类CA的构造函数没有获得执行。所以$b->name和$->age就不会初始化值。须要另外赋值$b->name='Jack',$b->age=25;
若是这时要执行父类CA的构造函数,能够这样:
因为parent::__construct($n); 只会向上搜索父类的构造函数,一找到就中止且执行当前找到的构造函数,所以在上面例子中,若是parent::__construct($n)是用在最后一层的类cC中,而且类CB,CA都有构造函数,那么cC的实例只会执行cB的构造函数。不会执行cA。这时,若是CC的实例想都调用CA和CB的构造函数,有两种方法:
A、在CB中也加入parent::__construct($n)
B、在CC中把构造函数改成:
(二)在子类中调用父类的属性或方法:
一、调用父类方法:在子类中调用父类的方法,有3种方法:
$this->ParentFunction(); 或
父类名::ParentFunction(); 或
parent::parentFun();
二、调用父类属性:只能用$this->ParentProperty;
(三)重载:
在子类中,能够定义与父类相同属性或方法,改变父类该属性或方法的值或操做,称作重载。如:
calss ParClass{ function pfun(){ ….}}
class ChildrenClass extends ParClass{function pfun(){ ….}}} //重载了父类的pfun的方法。
在子类中重载后,优先执行本身重载后的新定义的方法或属性。
也能够在子类中用parent::parentFun();调用父类的方法,但所获得的值是子类本身输入的参数运算值。而不是该方法在父类中运算的值。
3、接口:
接口:interface,能够理解成一组功能的共同规范,最大意义可能就是在多人协做时,为各自的开发规定一个共同的方法名称。
和抽象类中的抽象方法同样:
一、不能在接口中对方法具体实现进行定义。而是由具体类来实现(而抽象类中的非抽象方法能够没必要再定义,只有抽象方法和接口是同样要求要在具体类中实现)。
二、和抽象类同样,能够在接口中定义常量,并由具体类直接继承。
三、具体类必须实现抽象类的全部抽象方法(非抽象方法除外),一样,具体类如经过implements实现了接口后,必须完成接口中的全部方法。
接口实现过程:一、定义接口,二、用..implement X,Y,…和具体类对接。
class age implements Info //如要多个接口 class age (extends emJob) implements Info,interB…
{
public $age=15;
public $name='Join';
function getage() {
echo “年级是$this->age”;
}
function getname() {
echo “姓名是$this->name”;
}
function getN(){
echo ‘<h3>在接口中定义的常量N的值是:'.$this::N.' </h3>'; //直接继承接口中的常量值。
}
}
$age=new age;
echo $age::N; //22,直接调用接口中的常量值。
$age->getN();
关于抽象类和接口类的使用区分:什么时候用接口,什么时候用抽象?
一、相关性:当建立的模型由一些紧密相关的对象采用时,用抽象。对于不相关对象采用的功能,用接口。
二、多重继承:PHP类能够继承多个接口,但不能扩展多个抽象类。
三、公共行为实现:抽象类可在其中实现公共的方法,但接口不行。
4、命名空间(PHP6)
类库脚本A.inc.php和脚本B.inc.php中都一个类的名称为 class CNAME,而且这两个文件要在同一个文件如index.php中被调用。这时要用到命名空间。
步聚:
一、打开上面的A和B两个文件,分别在上面的最前面各加一行:
namespace SPACEA; 和 namespace SPACEB; 名字自定。
二、在index.php中实例化类时,在类的前面添加命名空间和双冒号作为前缀:
include ‘a.inc.php';
include ‘b.inc.php';
$a=new SPACEA::CNAME();
$b=new SPACEB::CNAME();
这样就不会冲突了。
但在PHP6正式发布前,这个功能还未定下来。
5、实现迭代器和迭代。
参《PHP圣经》P142;
6、使用Reflection(反射)API 。
简易实例:
class a{ …. }
$c = new ReflectionClass(‘a'); //PHP 内置类。
echo ‘<pre>'.$c.'</pre>';
输出类a的结构和内容。参《PHP圣经》P145;
/*************************************************************************************************************/
类的高级功能未学习