php 类
用php以来,一直怀念java的类和对象,终于PHP 5 引入了新的对象模型(Object Model)。完全重写了 PHP 处理对象的方式,向java靠齐了。下面来了解下吧!
一、定义类和实例化对象
php以关键字class来定义类,使用new来创建一个对象的实例,这就不用多说了。
二、自动加载对象机制
以前,我们引用对象,都要在前面使用include或者require将类包含进来,有时一个页面引用的类多了,感觉很麻烦,php5种,不再需要这样了,我们可以定义一个__autoload函数,它会在试图使用尚未被定义的类时自动调用。这就省得我们在每个页面都要使用一堆的包含函数了。
使用实例:
类文件:/class/class.testOne.php
<?php
class testOne{
function __construct(){
echo "begin";
}
function __destruct() {
}
}
?>
类文件:/class/class.testTwo.php
<?php
class testTwo{
protected $name;
function __construct(){
echo "conn";
}
function setName( $name ){
$this->name = $name;
}
function getName(){
return "My name is:".$this->name;
}
function __destruct() {
}
}
?>
文件:/comm.config.php
<?php
function __autoload( $class_name) {
require_once "./class/class.".$class_name.'.php';
}
?>
文件:/index.php
<?php
require_once( "comm.config.php" );
$testOne = new testOne();
?>
输出结果:begin
文件:/index2.php
<?php
require_once( "comm.config.php" );
$testTwo = new testTwo();
$testTwo->setName( "test" );
echo $testTwo->getName();
?>
输出结果:connMy name is:test
三、构造函数和析构函数
构造函数:void __construct ( [mixed args [, ...]] )
具有构造函数的类会在每次创建对象时先调用此方法,我们可以在这里做一些初始化操作。
析构函数:void __destruct ( void )
PHP 5 引入了析构函数的概念,这类似于其它面向对象的语言,如 C++。析构函数会在到某个对象的所有引用都被删除或者当对象被显式销毁时执行。
注意:
在继承父类的子类中,默认子类是不会实现父类的构造函数和析构函数,要执行父类的构造函数和析构函数,我们可以使用parent关键字在子类的构造函数和析构函数体中显式调用parent::__construct()和parent::__destruct()。
四、属性和方法的可见性
在php5中,我们可以像java一样,使用public、private、protected关键字来定义属性或者方法的可见性范围。
public:声明方法和属性可以被随意访问。
Protected:声明的方法和属性只能被类本身和其继承子类访问。
private:只能被定义属性和方法的类访问。
实例:
文件:class.testOne.php
<?php
class testOne{
public $public = "testOne.public";
protected $protected = "testOne.preteced";
private $private = "testOne.private";
function __construct(){
}
public function getPublic(){
return "From testOne.getPublic:".$this->public;
}//end
protected function getProtected(){
return "From testOne.getProtected:".$this->protected;
}
private function getPrivate(){
return "From testOne.getPrivate:".$this->private;
}
function printAll(){
echo $this->public.BR;
echo $this->getPublic().BR;
echo $this->protected.BR;
echo $this->getProtected().BR;
echo $this->private.BR;
echo $this->getPrivate().BR;
}
function __destruct() {
}
}
?>
文件:index.php
<?php
require_once( "class.testOne.php" );
$testOne = new testOne();
### 属性
echo $testOne->public.BR;
echo $testOne->protected.BR; //Fatal error: Cannot access protected property testOne::$protected in E:/www3/test/index.php on line 6
echo $testOne->private.BR; //Fatal error: Cannot access private property testOne::$private in E:/www3/test/index.php on line 7
### 方法
echo $testOne->getPublic().BR;
echo $testOne->getProtected().BR;//Fatal error: Call to protected method testOne::getProtected() from context '' in E:/www3/test/index.php on line 10
echo $testOne->getPrivate().BR;//Fatal error: Call to private method testOne::getPrivate() from context '' in E:/www3/test/index.php on line 11
### 内部访问
$testOne->printAll();
echo "-----------------".BR;
### 定义扩展类
class SunClass extends testOne{
protected $protected = 'SunClass.protected';
function printAll(){
echo $this->public.BR;
echo $this->getPublic().BR;
echo $this->protected.BR;
echo $this->getProtected().BR;
echo $this->private.BR;//这里不报错,但是值是空的
echo $this->getPrivate().BR;//Fatal error: Call to private method testOne::getPrivate() from context 'SunClass' in E:/www3/test/index.php on line 25
}
}
### 子类访问
$obj2 = new SunClass();
$obj2->printAll();
?>
正常无错误的输出如下:
testOne.public
From testOne.getPublic:testOne.public
testOne.public
From testOne.getPublic:testOne.public
testOne.preteced
From testOne.getProtected:testOne.preteced
testOne.private
From testOne.getPrivate:testOne.private
-----------------
testOne.public
From testOne.getPublic:testOne.public
SunClass.protected
From testOne.getProtected:SunClass.protected
以上实例说名:
public或者默认无声明的属性和方法无论怎么样都可以被访问到。
protected的属性和方法只能在类内部或者继承子类内部访问。
private的属性和方法只能在类自身内部访问。
五、static关键字
将一个类的属性或者方法定义为static,则可以在不实例化类的情况下使用类的属性和方法。
注意:
1、static关键字必须在public、protected、private之后声明。
2、子类不能重新定义父类中static关键字修饰的变量属性或者方法,除非你将它们定义为static成员。
3、static方法或者变量中,$this 变量是不可用的,如果你要使用同一类中其他的定义为static变量或者方法,可以使用self::(变量名|方法名)来访问static成员。
4、Static成员属性不能以$object->(static成员属性)方式访问,你可以$类名::(static成员属性)访问它们。这里跟java不同,PHP中static成员是不能被类的实例对象访问的。
实例:
<?php
require_once( "comm.config.php" );
class Foo
{
public static $my_static = 'foo';
public function staticValue() {
###echo $this->$my_static; //(不能使用$this变量访问static成员)Fatal error: Cannot access empty property in E:/www3/test/index.php on line 8
return self::$my_static;
}
}
class Bar extends Foo
{
###public static $my_static;//Fatal error: Cannot redeclare static Foo::$my_static as non static Bar::$my_static in E:/www3/test/index.php on line 20(在public后面加上static关键字就ok了)
public function fooStatic() {
return self::$my_static;
}
}
$foo = new Foo();
print $foo->staticValue() . "/n";
print Foo::$my_static . "/n";
print $foo->my_static . "/n"; // my_static属性是空的。
echo "<br>";
// $foo::my_static is not possible
print Bar::$my_static. "/n";
print Bar::staticValue(). "/n";
$bar = new Bar();
print $bar->fooStatic() . "/n";
?>
正确的输出结果:
foo foo
foo foo foo
六、作用域分辨运算符(::)
在没有声明任何实例的情况下使用::来访问类中的函数或者基类中的函数和变量。
一般用在以下三种情况
1、从类外部不经过实例化访问类成员(比如static或者常量),
使用格式:类名::成名名;
2、类内部使用,通过关键字self和parent来实现类内部访问类定义的成员.
3、子类通过关键字parent来访问父类成员。
实例:
class FatherClass
{
const CONST_VALUE = 'FatherClass.const';
static $static = "FatherClass.static";
private function goPrivate(){
echo "FatherClass.goPrivate<br>";
}
protected function goProtected() {
echo "FatherClass.goProtected<br>";
}
function goPublic() {
echo "FatherClass.goPublic<br>";
self::goPrivate();//self关键字访问内部私有方法
self::goProtected();//self关键字访问内部保护方法
echo self::CONST_VALUE."<br>";//self访问类内部常量
echo self::$static."<br>";//self访问类内部static变量
}
}
class SunClass extends FatherClass
{
function goPrivate(){
echo "重载父类方法:SunClass.goPrivate<br>";
###parent::goPrivate();//Fatal error
parent::goProtected(); //parent访问父类protected方法
echo parent::CONST_VALUE."<br>";//parent访问父类常量
echo parent::$static."<br>";//parent访问父类static变量
}
}
###FatherClass::goPrivate();//这里会出现Fatal error:,因为private修饰的成员外部是不能访问的。
###FatherClass::goProtected();//这里会出现Fatal error:,因为protected修饰的成员外部是不能直接访问的,只有子类或者类本身才能访问。
echo FatherClass::CONST_VALUE."<br>";//通过::访问到类内部常量
echo FatherClass::$static."<br>";//访问类的static变量
FatherClass::goPublic();//访问类成员方法
$sunclass = new SunClass();
$sunclass->goPrivate();
输出结果:
FatherClass.const
FatherClass.static
FatherClass.goPublic
FatherClass.goPrivate
FatherClass.goProtected
FatherClass.const
FatherClass.static
重载父类方法:SunClass.goPrivate
FatherClass.goProtected
FatherClass.const
FatherClass.static
七、类常量
我们可以通过定义类常量使得类的每个实例化对象中,成员的值都是相同的,而且对象不能改变它的值。
常量和其他变量的区别主要在于:
1.类的实例化对象是不能改变常量的值,并且每个实例化对象的常量值都是相同的。
2.不需要$符号来声明和使用常量。
3.常量不能被类的实例化对象直接使用,它只能在类内部使用。这点跟static成员是一相同的。
实例:
class MyClass
{
const constant = 'constant value';
function showConstant() {
//self::constant = "change constant value"; ###会出现错误
echo self::constant . "/n";
}
}
echo MyClass::constant . "/n";
$class = new MyClass();
$class->showConstant();
//echo $class::constant; ###is not allowed
八、抽象类
PHP5中引入了abstract类和方法的概念。一个类被声明为abstract,则此类是不能被实例化的。
如果在一个类内部有一个成员方法被声明成abstract,则这个类也必须是抽象类。
而且抽象成员方法只能定义方法的名称,不能定义方法的实现细节,这些方法的实现细节是留待继承
此抽象类的子类去实现的。子类继承抽象类时,除非子类仍然声明为抽象类,否则就必须实现抽象类中
所有声明为abstract的成员方法。注意,子类在是实现抽象类的抽象成员时,子类成员的可见性必须
和抽象类保持一致或者小于抽象类的成员可见性。
比如:抽象方法定义为protected,则实现此抽象方法的子类必须声明为protected或者public,而不能声明为private。
实例:
//class AbstractClass ###如果去掉abstract关键字将出现错误
abstract class AbstractClass
{
// Force Extending class to define this method
abstract protected function getValue();
abstract protected function prefixValue($prefix);
// Common method
public function printOut() {
print $this->getValue() . "/n";
}
}
class ConcreteClass1 extends AbstractClass
{
//private function getValue(){ ###如果声明为private 会出现错误
public function getValue() {
return "ConcreteClass1";
}
public function prefixValue($prefix) {
return "{$prefix}ConcreteClass1";
}
}
//$class = new AbstractClass();###出现错误,抽象类不能被实例化
$class1 = new ConcreteClass1;
$class1->printOut();
echo $class1->prefixValue('FOO_') ."/n";
九、接口
接口允许你创建一个只有方法声明,而无具体实现的类对象.接口是一系列方法的声明,是一些方法特征的集合,
一个接口只有方法的特征没有方法的实现,因此这些方法可以在不同的地方被不同的类实现,
而这些实现可以具有不同的行为(函数)。 接口把方法的特征和方法的实现分割开来。这种分割体现在接口常常代表一个角色,
它包装与该角色相关的操作和属性,而实现这个接口的类便是扮演这个角色的演员。一个角色由不同的演员来演,而不同的演员之间除了扮演一个共同的角色之外,
并不要求其它的共同之处。
注:
1、接口由interface关键字声明。
2、接口的所有方法作用域必须是public的。
3、接口只定义方法,没有任何有实际意义的代码,具体的代码由实现这个接口的类来完成。
4、实现类通过implements来实现接口,接口所定义的方法,实现类必须全部实现。
5、实现类可以实现多个接口,只需要将接口用逗号隔开即可。
6、对象是对某类的事物的抽象,接口是对对象的抽象,接口用来标志类的类别。
7、接口是不能实例化的。
实例:
// 声明接口'iFaceOne'
interface iFaceOne
{
public function setVariable($name, $var);
public function getVariable( $name );
}
// 声明接口'iFaceTwo'
interface iFaceTwo
{
public function getHtml( $str );
}
//声明接口'iFaceTwoSun'继承iFaceTwo接口,扩展setHtml方法
interface iFaceTwoSun extends iFaceTwo{
public function setHtml();
}
//类one实现iFaceOne、iFaceTwo接口
class one implements iFaceOne,iFaceTwo
{
private $test = "";
//实现iFaceOne接口的setVariable方法
public function setVariable( $name,$var ){
echo "one实现iFaceOne.setVariable<BR>";
$this->$name = $var;
}
//实现iFaceOne接口的getVariable方法
public function getVariable( $name ){
echo "one实现iFaceOne.getVariable<BR>";
return $this->$name;
}
//实现iFaceTwo接口的getHtml方法
public function getHtml( $str ){
echo "one实现iFaceTwo.getHtml<BR>";
return $str;
}
}
//类two实现iFaceTwo接口
class two implements iFaceTwoSun{
public function getHtml( $str ){
echo "two实现iFaceTwo.getHtml<BR>";
return $str;
}
public function setHtml(){
echo "two实现iFaceTwoSun.getHtml<BR>";
}
}
class three{
function get(iFaceTwo $Obj,$str ){
return $Obj->getHtml( $str );
}
function set( iFaceTwo $Obj ){
return $Obj->setHtml();
}
}
$three = new three();
$one = new one();
$two = new two();
//$iFaceOne = new iFaceOne(); //报错,因为接口是不能被实例化的
$one->setVariable( "test","one" );
$rs = $one->getVariable( "test" );
echo $rs."<hr>";
$rs = $two->getHtml( "two" );
echo $rs."<br>";
$rs = $two->setHtml();
echo "<hr>";
$rs = $three->get( $one,"one" );
echo $rs."<hr>";
$rs = $three->set( $two,"two" );
echo $rs."<hr>";
/*********************/
//$three->setHTML( $one );//报错
$three->set( $two );