php对象
对象
在类定义内部,可以用 new self 和 new parent 创建新对象。
当把一个对象已经创建的实例赋给一个新变量时,新变量会访问同一个实例,就和用该对象赋值一样。可以用克隆给一个已创建的对象建立一个新实例。
<?php
$instance = new SimpleClass();
$assigned = $instance;
$reference =& $instance;
$instance->var = '$assigned will have this value';
$instance = null; // $instance and $reference become null
var_dump($instance);
var_dump($reference);
var_dump($assigned);
?>
输出:
NULL
NULL
object(SimpleClass)#1 (1) {
["var"]=>
string(30) "$assigned will have this value"
}
PHP 5.3.0 引进了两个新方法来创建一个对象的实例:
<?php
class Test
{
static public function getNew()
{
return new static;
}
}
$obj1 = new Test();
$obj2 = new $obj1; //第一种
$obj3 = Test::getNew();
自 PHP 5.5 起,使用 ClassName::class 你可以获取一个字符串,包含了类 ClassName 的完全限定名称。这对使用了 命名空间 的类尤其有用。
类常量
可以把在类中始终保持不变的值定义为常量。在定义和使用常量的时候不需要使用 $ 符号
<?php
class MyClass
{
const constant = 'constant value';
function showConstant() {
echo self::constant . "\n";
}
}
静态属性不能通过一个类已实例化的对象来访问(但静态方法可以)
抽象类
任何一个类,如果它里面至少有一个方法是被声明为抽象的,那么这个类就必须被声明为抽象的。
<?php
abstract class AbstractClass
{
// 强制要求子类定义这些方法
abstract protected function getValue();
abstract protected function prefixValue($prefix);
// 普通方法(非抽象方法)
public function printOut() {
print $this->getValue() . "\n";
}
}
Trait
传统继承增加了水平特性的组合,避免传统多继承和 Mixin 类相关典型问题。优先级:当前类的成员覆盖了 trait 的方法,而 trait 则覆盖了被继承的方法。
<?php
trait ezcReflectionReturnInfo {
function getReturnType() { /*1*/ }
function getReturnDescription() { /*2*/ }
}
class ezcReflectionMethod extends ReflectionMethod {
use ezcReflectionReturnInfo;
/* ... */
}
class ezcReflectionFunction extends ReflectionFunction {
use ezcReflectionReturnInfo;
/* ... */
}
多个 trait
通过逗号分隔,在 use 声明列出多个 trait,可以都插入到一个类中。
<?php
trait Hello {
public function sayHello() {
echo 'Hello ';
}
}
trait World {
public function sayWorld() {
echo 'World';
}
}
class MyHelloWorld {
use Hello, World;
public function sayExclamationMark() {
echo '!';
}
}
$o = new MyHelloWorld();
$o->sayHello();
$o->sayWorld();
解决trait冲突
如果两个 trait 都插入了一个同名的方法,如果没有明确解决冲突将会产生一个致命错误。
需要使用 insteadof 操作符来明确指定使用冲突方法中的哪一个。as 操作符可以将其中一个冲突的方法以另一个名称来引入。
示例:定义了使用 trait B 中的 smallTalk 以及 trait A 中的 bigTalk,用了 as 操作符来定义了 talk 来作为 B 的 bigTalk 的别名。
<?php
trait A {
public function smallTalk() {
echo 'a';
}
public function bigTalk() {
echo 'A';
}
}
trait B {
public function smallTalk() {
echo 'b';
}
public function bigTalk() {
echo 'B';
}
}
class Aliased_Talker {
use A, B {
B::smallTalk insteadof A;
A::bigTalk insteadof B;
B::bigTalk as talk;
}
}
修改访问控制权限
使用as
<?php
trait HelloWorld {
public function sayHello() {
echo 'Hello World!';
}
}
// 修改 sayHello 的访问控制
class MyClass1 {
use HelloWorld { sayHello as protected; }
}
// 给方法一个改变了访问控制的别名
// 原版 sayHello 的访问控制则没有发生变化
class MyClass2 {
use HelloWorld { sayHello as private myPrivateHello; }
}
?>
其他
其它 trait 也能够使用 trait。
trait 支持抽象方法的使用。
Trait 同样可以定义属性。
匿名类
匿名类被嵌套进普通 Class 后,不能访问这个外部类(Outer class)的 private(私有)、protected(受保护)方法或者属性。 为了访问外部类(Outer class)protected 属性或方法,匿名类可以 extend(扩展)此外部类。 为了使用外部类(Outer class)的 private 属性,必须通过构造器传进来:
<?php
class Outer
{
private $prop = 1;
protected $prop2 = 2;
protected function func1()
{
return 3;
}
public function func2()
{
return new class($this->prop) extends Outer {
private $prop3;
public function __construct($prop)
{
$this->prop3 = $prop;
}
public function func3()
{
return $this->prop2 + $this->prop3 + $this->func1();
}
};
}
}
echo (new Outer)->func2()->func3();
魔术方法
不可访问属性、不可访问方法:未定义或不可见的类属性或方法
在给不可访问属性赋值时,__set() 会被调用。
读取不可访问属性的值时,__get() 会被调用。
当对不可访问属性调用 isset() 或 empty() 时,__isset() 会被调用。
当对不可访问属性调用 unset() 时,__unset() 会被调用。
在对象中调用一个不可访问方法时,__call() 会被调用。
在静态上下文中调用一个不可访问方法时,__callStatic() 会被调用。
serialize() 函数会检查类中是否存在一个魔术方法 __sleep()。如果存在,该方法会先被调用,然后才执行序列化操作。此功能可以用于清理对象,并返回一个包含对象中所有应被序列化的变量名称的数组。
unserialize() 会检查是否存在一个 __wakeup() 方法。如果存在,则会先调用 __wakeup 方法,预先准备对象需要的资源。
public void __set ( string $name , mixed $value )
public mixed __get ( string $name )
public bool __isset ( string $name )
public void __unset ( string $name )
public mixed __call ( string $name , array $arguments )
public static mixed __callStatic ( string $name , array $arguments )
__construct(), __destruct(), __sleep(), __wakeup(), __toString(), __invoke(),__set_state(), __clone() , __debugInfo()
示例:
<?php
class PropertyTest {
/** 被重载的数据保存在此 */
private $data = array();
/** 重载不能被用在已经定义的属性 */
public $declared = 1;
/** 只有从类外部访问这个属性时,重载才会发生 */
private $hidden = 2;
public function __set($name, $value)
{
echo "Setting '$name' to '$value'\n";
$this->data[$name] = $value;
}
public function __get($name)
{
echo "Getting '$name'\n";
if (array_key_exists($name, $this->data)) {
return $this->data[$name];
}
$trace = debug_backtrace();
trigger_error(
'Undefined property via __get(): ' . $name .
' in ' . $trace[0]['file'] .
' on line ' . $trace[0]['line'],
E_USER_NOTICE);
return null;
}
/** PHP 5.1.0之后版本 */
public function __isset($name)
{
echo "Is '$name' set?\n";
return isset($this->data[$name]);
}
/** PHP 5.1.0之后版本 */
public function __unset($name)
{
echo "Unsetting '$name'\n";
unset($this->data[$name]);
}
/** 非魔术方法 */
public function getHidden()
{
return $this->hidden;
}
}
call示例:arguments是一个数组
<?php
class MethodTest
{
public function __call($name, $arguments)
{
// 注意: $name 的值区分大小写
var_dump($arguments);
}
/** PHP 5.3.0之后版本 */
public static function __callStatic($name, $arguments)
{
// 注意: $name 的值区分大小写
var_dump($arguments);
}
}
$obj = new MethodTest;
$obj->runTest('in object context','fyfy');
MethodTest::runTest('in static context'); // PHP 5.3.0之后版本
?>
//输出类似
/*
array(2) {
[0] =>
string(17) "in object context"
[1] =>
string(4) "fyfy"
}
array(1) {
[0] =>
string(17) "in static context"
}
*/
遍历对象
默认情况下,所有可见属性都将被用于遍历。
<?php
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();
?>
对象复制
clone 关键字,浅复制(shallow copy)。所有的引用属性 仍然会是一个指向原来的变量的引用。当复制完成时,如果定义了 __clone() 方法,则新创建的对象(复制生成的对象)中的 __clone() 方法会被调用,可用于修改属性的值(如果有必要的话)。
示例:关于浅复制
<?php
class subclass{
public $var1='subclass default';
}
class MyClass
{
public $var1 = 'myclass default';
public $object;
function __construct(){
$this->object=new subclass();
}
}
$object1 = new MyClass();
$object2 = clone $object1;
$object1->object->var1='object1 change';
$object1->var1='object1 change';
print_r($object1);
print_r($object2);
?>
输出结果:
MyClass Object
(
[var1] => object1 change
[object] => subclass Object
(
[var1] => object1 change
)
)
MyClass Object
(
[var1] => myclass default
[object] => subclass Object
(
[var1] => object1 change
)
对象比较
==:两个对象的属性和属性值 都相等,而且两个对象是同一个类的实例,那么这两个对象变量相等。
===:必须是同一个对象。