对属性或方法的访问控制,是通过在前面添加关键字 public(公有),protected(受保护)或 private(私有)来实现的。
函数原型:
__construct ([ mixed $args [, $... ]] ) : void
__destruct ( void ) : void
作用:
示例:
class BaseClass {
function __construct() {
print "In BaseClass constructor\n";
}
}
class SubClass extends BaseClass {
function __construct() {
parent::__construct();
print "In SubClass constructor\n";
}
}
class OtherSubClass extends BaseClass {
// inherits BaseClass's constructor
}
// In BaseClass constructor
$obj = new BaseClass();
// In BaseClass constructor
// In SubClass constructor
$obj = new SubClass();
// In BaseClass constructor
$obj = new OtherSubClass();
?>
划重点:
关键字:extends
规则:
PHP 5.4.0 起,实现了一种代码复用的方法,称为 trait(特性),便于在不同层次结构内实现代码复用。不用通过extends关键字继承即可在一个类中使用另一个类的方法。
示例:
trait ezcReflectionReturnInfo {
function getReturnType() { /*1*/ }
function getReturnDescription() { /*2*/ }
}
class ezcReflectionMethod extends ReflectionMethod {
use ezcReflectionReturnInfo;
/* ezcReflectionMethod中可以使用 ezcReflectionReturnInfo中的方法*/
}
class ezcReflectionFunction extends ReflectionFunction {
use ezcReflectionReturnInfo;
/* ... */
}
?>
trait Win
{
public function exec(){
echo "Win exec";
}
}
trait Mac
{
public function exec(){
echo "Mac exec";
}
}
trait Config
{
public function filename(){
echo "php.ini";
}
}
class Php{
use Config {
Config::filename as configFilename;
}
use Win,Mac {
Win::exec insteadof Mac;
}
}
用于访问类的静态成员,常量类型,还可以用于在子类中显示访问父类中被子类覆盖的属性和方法(包括构造方法和析构方法)。
class MyClass {
const CONST_VALUE = 'A constant value';
protected function myFunc() {
echo "MyClass::myFunc()\n";
}
}
class OtherClass extends MyClass
{
public static $my_static = 'static var';
public static function doubleColon() {
echo parent::CONST_VALUE . "\n"; //访问父类的常量
echo self::$my_static . "\n"; //访问自己的静态属性
}
// 覆盖了父类的定义
public function myFunc()
{
parent::myFunc(); // 访问父类中被覆盖的方法
echo "OtherClass::myFunc()\n";
}
}
//在类外部访问常量成员
echo MyClass::CONST_VALUE;
//在类外部访问静态方法
OtherClass::doubleColon();
$class = new OtherClass();
//OtherClass中的myFunc()
$class->myFunc();
class Test {
public static $a = 1;
public $b = 1;
public function __construct() {
++ self::$a;
++ $this->b;
}
public function getA() {
echo self::$a;
}
public function getB() {
echo $this->b;
}
}
$test1 = new Test();
$test1->getA(); //2
$test1->getB(); //2
$test2 = new Test();
$test2->getA(); //3
$test2->getB(); //2
全局变量、静态全局变量、静态局部变量和局部变量的区别:
变量可以分为:全局变量、静态全局变量、静态局部变量和局部变量。
按存储区域分:全局变量、静态全局变量和静态局部变量都存放在内存的静态
存储区域,局部变量存放在内存的栈区。
按作用域分:全局变量在整个工程文件内都有效;静态全局变量只在定义它的
文件内有效;静态局部变量只在定义它的函数内有效,只是程序仅分配一次内存,
函数返回后,该变量不会消失;局部变量在定义它的函数内有效,但是函数返回
后失效。
示例1:
abstract class AbstractClass
{
//抽象方法
abstract protected function getValue();
abstract protected function prefixValue($prefix);
//普通方法
public function printOut() {
print $this->getValue() . "\n";
}
}
class ConcreteClass1 extends AbstractClass
{
protected function getValue() {
return "ConcreteClass1";
}
public function prefixValue($prefix) {
return "{$prefix}ConcreteClass1";
}
}
class ConcreteClass2 extends AbstractClass
{
public function getValue() {
return "ConcreteClass2";
}
public function prefixValue($prefix) {
return "{$prefix}ConcreteClass2";
}
}
$class1 = new ConcreteClass1;
$class1->printOut(); //ConcreteClass1
echo $class1->prefixValue('FOO_') ."\n"; //FOO_ConcreteClass1
$class2 = new ConcreteClass2;
$class2->printOut(); //ConcreteClass2
echo $class2->prefixValue('FOO_') ."\n"; //FOO_ConcreteClass2
示例2:子类实现的父类抽象方法参数可不同
abstract class AbstractClass
{
// 我们的抽象方法仅需要定义需要的参数
abstract protected function prefixName($name);
}
class ConcreteClass extends AbstractClass
{
// 我们的子类可以定义父类签名中不存在的可选参数
public function prefixName($name, $separator = ".") {
if ($name == "Pacman") {
$prefix = "Mr";
} elseif ($name == "Pacwoman") {
$prefix = "Mrs";
} else {
$prefix = "";
}
return "{$prefix}{$separator} {$name}";
}
}
$class = new ConcreteClass;
echo $class->prefixName("Pacman"), "\n"; //Mr. Pacman
echo $class->prefixName("Pacwoman"), "\n"; //Mrs. Pacwoman
关键字:interface(定义接口)、implements(实现接口)、extends(继承接口)
实现接口的类必须实现接口类中的所有接口,除非它自己定义为abstract类。
示例1:
interface Test {
public function f1();
public function f2();
}
abstract class AbTest implements Test {
public function f1() {
echo 1;
}
abstract public function f3();
}
class SubTest extends AbTest {
public function f1() {
echo 2;
}
public function f2() {
}
public function f3() {
}
}
$test = new SubTest();
$test->f1(); //2
示例2:可以继承多个接口
interface a
{
public function foo();
}
interface b
{
public function bar();
}
interface c extends a, b
{
public function baz();
}
class d implements c
{
public function foo()
{
}
public function bar()
{
}
public function baz()
{
}
}
从PHP7开始支持匿名类
$obj = new class {
public function b($a) {
return $a;
}
}
echo $obj->b('a');
子类覆盖父类方法的原则:
class MyClass
{
public $a = 1;
protected $b = 2;
private $c = 3;
public function f1() {
echo "MyClass f1".'
';
echo "a->$this->a; b->$this->b; c->:$this->c;".'
';
}
protected function f2() {
echo "MyClass f2".'
';
echo "a->$this->a; b->$this->b; c->:$this->c;".'
';
}
private function f3() {
echo "MyClass f3\n".'
';
}
}
class MySubClass extends MyClass
{
public $b = 22;
public $c = 33;
public function f1() {
echo "MySubClass f1\n".'
';
//首先在自己的类变量中找,没找到则访问父类的变量(可以访问的前提下,否则返回空)
echo "a->$this->a; b->$this->b; c->:$this->c;".'
';
//此时父类f1中的this指向的是MySubClass类
parent::f1();
//此时父类f1中的this指向的是MySubClass类
$this->f2();
}
// 父类的f3()是私有的,这里的定义与父类无关
public function f3() {
echo "MySubClass f3\n".'
';
}
}
$b = new MySubClass;
$b->f1();
echo "\n".'
';
/*
MySubClass f1
$a:1; $b:22; $c:33;
MyClass f1
$a:1; $b:22; $c:3;
MyClass f2
$a:1; $b:22; $c:3;
*/
$b->f3();echo "\n";
/*
MySubClass f3
*/
PHP中的重载与其它绝大多数面向对象语言不同。传统的重载是用于提供多个同名的类方法,但各方法的参数类型和个数不同。
PHP中的重载是指动态地“创建”类属性和方法。通过魔术方法(magic methods)来实现。当调用当前环境下未定义或不可见的类属性或方法时,重载方法会被调用。
所有的重载方法都必须被声明为 public。
/**
* 魔术方法
* __get() 访问不可访问的属性或方法(未定义或不可见的类属性或方法)时被调用
* __set() 给不可访问的属性(未定义或不可见的类属性)赋值时被调用
*/
class ParentTest {
public function getAddress() {
return "
"."this is address";
}
}
class Person extends ParentTest{
//访问不可访问的属性时被调用
function __get($propety) {
$method = "get{$propety}";
if(method_exists($this, $method)) {
return $this->$method();
}
}
private function getName() {
return "
"."this is name";
}
function getAge() {
return "
"."this is age";
}
}
$test = new Person();
echo $test->name; // "this is name"
echo $test->address; // "this is address"
例如用 foreach 语句遍历对象,默认情况下,所有可见属性都将被用于遍历。
class MyClass
{
public $var1 = 'value 1';
public $var2 = 'value 2';
public $var3 = 'value 3';
protected $protected = 'protected var';
private $private = 'private var';
function iterateVisible() {
echo "MyClass::iterateVisible:\n";
foreach($this as $key => $value) {
print "$key => $value\n";
}
}
}
$class = new MyClass();
foreach($class as $key => $value) {
print "$key => $value\n";
}
echo "\n";
$class->iterateVisible();
/*
var1 => value 1
var2 => value 2
var3 => value 3
MyClass::iterateVisible:
var1 => value 1
var2 => value 2
var3 => value 3
protected => protected var
private => private var
*/
用等号复制对象,并没有为等号左值b开辟新的空间,只是让其指向(引用)了等号右值a所指向的空间。通过b修改对象的某个属性,当利用a访问该属性时,发现这个值被修改了。这称为浅拷贝。
可以利用clone关键字来完成深拷贝,如果实现了__clone()方法,该方法将被调用。
class Test
{
public $num = "test";
public function __construct() {
echo "call __construct";
}
public function __clone() {
echo "call __clone";
}
}
$test1 = new Test();
$test2 = $test1;
$test2->num = "test2";
echo $test1->num;
$other1 = new Test();
$other2 = clone $other1;
$other2->num = "other2";
echo $other1->num;
/*
call __construct
test2
call __construct
call __clone
test
*/
function bool2str($bool)
{
if ($bool === false) {
return 'FALSE';
} else {
return 'TRUE';
}
}
function compareObjects(&$o1, &$o2)
{
echo 'o1 == o2 : ' . bool2str($o1 == $o2) . "\n";
echo 'o1 != o2 : ' . bool2str($o1 != $o2) . "\n";
echo 'o1 === o2 : ' . bool2str($o1 === $o2) . "\n";
echo 'o1 !== o2 : ' . bool2str($o1 !== $o2) . "\n";
}
class Flag
{
public $flag;
function Flag($flag = true) {
$this->flag = $flag;
}
}
class OtherFlag
{
public $flag;
function OtherFlag($flag = true) {
$this->flag = $flag;
}
}
$o = new Flag();
$p = new Flag();
$q = $o;
$r = new OtherFlag();
echo "Two instances of the same class\n";
compareObjects($o, $p);
echo "\nTwo references to the same instance\n";
compareObjects($o, $q);
echo "\nInstances of two different classes\n";
compareObjects($o, $r);
/*
Two instances of the same class
o1 == o2 : TRUE
o1 != o2 : FALSE
o1 === o2 : FALSE
o1 !== o2 : TRUE
Two references to the same instance
o1 == o2 : TRUE
o1 != o2 : FALSE
o1 === o2 : TRUE
o1 !== o2 : FALSE
Instances of two different classes
o1 == o2 : FALSE
o1 != o2 : TRUE
o1 === o2 : FALSE
o1 !== o2 : TRUE
*/