1.在类的外部(非继承),只能访问共有(public)属性和方法。
class shopProduct{
protected $title="com";
public $name="main";
protected function getProducer(){
return $this->name;
}
}
$shopproduct=new shopProduct();
echo $shopproduct->name;//在类的外部只能访问publi属性
2.子类可以访问父类的非私有属性和方法,只有在类中才能访问private方法和属性
class shopProduct{
protected $title="com";
public $name="main";
protected function getProducer(){
return $this->name;
}
}
class chProduct extends shopProduct{
public function gettitle(){
return $this->title;//子类可以访问父类的非private属性和方法
}
}
$chproduct=new chProduct();
echo $chproduct->getch();
3.如果派生类没有定义构造方法,那么在实例化的时候会默认调用父类构造方法;如果子类定义了构造函数,需要同时调用父类构造函数,那么应该用parent::__construct()
class shopProduct{
public $title;
public $price;
function __construct($title,$price){
$this->title=$title;
$this->price=$price;
}
}
class chProduct extends shopProduct{
public $playlength;
function __construct($title,$price,$playlength){
parent::__construct($title,$price);
$this->playlength=$playlength;
}
function getsum(){
return "title:{$this->title},price:{$this->price},playlength:{$this->playlength}";
}
}
$chproduct=new chProduct(1,2,3);
echo $chproduct->getsum();
4.parent关键字可以在任何覆写父类方法的方法中使用。覆写一个父类的方法时,
我们并不希望删除父类的功能,而是扩展它。
function getSum(){
$base=parent::getSum();
$base.=":page count - {$this->numPages}";
return base;
}
5.一般来说,我们倾向于严格控制可访问性。最好将类的属性初始化为private或protected,然后在需要的时候再放松限制条件。类中的许多方法都可以是public,然后如果拿不定主意的话,就限制一下。有些类方法只为类中其他方法提供本地功能,与类外部的代码没有任何联系,应该将其设置为private或protected。
6.静态方法是以类为作用域的函数。静态方法不能访问这个类中的普通属性,因为那些属性属于一个对象,但可以访问静态属性。因为是通过类而不是实例来访问静态元素,所以访问静态元素时不需要引用对象的变量,而是使用::(两个冒号)来连接类名和属性或类名和方法。我们曾使用::和parent来访问覆写的方法。现在和之前一样,只不过访问的是类而不是对象数据。一个子类可以使用parent关键字来访问父类,而不使用其类名。要从当前类(不是子类)中访问静态方法或属性,可以使用self关键字。self指向当前类,就像伪变量$this指向当前对象一样。
class StaticExample{
static public $aNum=0;
static public function sayHello(){
print "hello";
}
}
print StaticExample::$aNum;
StaticExample::sayHello();
7.getInstance方法根据类型标志聪明的判断需要实例化的对象。这个方法就像“工厂”一样,这个就是工厂模式。
class shopProduct{
private $id=0;
public function setID($id){
$this->id=$id;
}
public static function getInstance($type){
if($type=="book"){
$product=new BookProduct();
}else if($type=="cd"){
$product=new CdProduct();
}else{
$product=new ShopProduct();
}
return $product;
}
}
8.常量属性,有些属性不能改变。在类中用const关键字来声明,与静态属性一样,只能通过类而不能通过类的实例访问常量属性。
class ShopProduct{
const AVAILABLE=0;
const OUT_OF_STOCK=1;
}
print ShopProduct::AVAILABLE;
9.抽象类不能被直接实例化,抽象类中只定义(或部分实现)子类需要的方法。子类可以继承它并且通过实现其中的抽象方法,使抽象类具体化。大多数情况下,抽象类至少包好一个抽象方法。抽象方法用abstract关键字声明,其中不能有具体内容。
abstract class ShopProductWriter{
protected $products=array();
public function addProduct(ShopProduct $shopProduct){
$this->products[]=$shopProduct;
}
abstract public function write();
}
创建抽象方法后,要确保所有子类中都实现了该方法。
10.抽象类提供了具体实现的标准,而接口则是纯粹的模板。接口只能定义功能,而不包含实现的内容。接口可用关键字interface来声明。接口可以包含属性和方法的声明,但是方法体为空。
interface Chareable{
public function getPrice();
}
class ShopProduct implements Chareable{
// ...
public function getPrice(){
return ($this->price-$this->discount);
}
// ...
}
11.错误处理,文件放错地方,数据库服务器未初始化,url有变动,xml文件损坏,这些问题时常发生。要对付这些可能出现的错误,一个简单的类方法有时会充满了错误处理代码。
class Conf{
private $file;
private $xml;
private $lastmatch;
function __construct($file){
$this->file=$file;
$this->xml=simplexml_load_file($file);
}
function write(){
file_put_contents($this->file,$this->xml->asXML());
}
}
可以使用throw关键字和Exception对象来抛出异常。这会停止执行当前方法,并负责将错误返回给调用代码。下面修改一下__construct和write方法,使其使用throw语句。
function __construct($file){
$this->file=$file;
if(!file_exists($file)){
throw new Exception("file does not exist");
}
$this->xml=simplexml_load_file($file);
}
function write(){
if(!is_writeable($this->file)){
throw new Exception("file is not writeable");
}
file_put_contents($this->file,$this->xml->asXML());
}
__construct()和write()方法现在可以在工作时不停地检查文件错误,但是代码还应该更好地对检测到的错误作出响应。
try{
$conf=new Conf(dirname(__FILE__)."/conf01.xml");
$conf->write();
}catch(Exception $e){
die($e->_toString());
}
当抛出异常时,调用作用域中的catch子句会被调用,自动将Exception对象作为参数变量传入。
异常的子类化:
class XmlException extends Exception{
private $error;
function __construct(LibXmlError $error){
$shortfile=basename($error->file);
$msg="[{$shortfile},line {$error->line},col {$error->col}] {$error->message}";
$this->error=$error;
parent::__construct($msg,$error->code);
}
function getLibXmlError(){
return $this->error;
}
}
class FileException extends Exception{}
class ConfException extends Exception{}
//Conf类
function __construct($file){
$this->file=$file;
if(!file_exists($file)){
throw new FileException("file does not exist");
}
$this->xml=simplexml_load_file($file,null,LIBXML_NOERROR);
if(!is_object($this->xml)){
throw new XmlException(libxml_get_last_error());
}
print gettype($this->xml);
$matches=$this->xml->xpath("/conf");
if(!conut($matches)){
throw new ConfException("could not find root element:conf");
}
}
function write(){
if(!is_writeable($this->file)){
throw new FileException("file is not writeable");
}
file_put_contents($this->file,$this->xml->asXML());
}
下面是实例化对象Conf的代码
class Runner{
static function init(){
try{
$conf=new Conf(dirname(__FILE__)."/conf01.xml");
$conf->write();
}catch(FileExcepiton $e){
//文件权限问题或文件不存在
}catch(XmlException $e){
//XML文件损坏
}catch(XmlException $e){
//错误的XML文件格式
}catch(Exception $e){
//后备捕捉器,正常情况下不应该被调用
}
}
}
11.final关键字可以防止覆写类或方法,final类不能有子类。
final class Checkout{
// ...
}
12.拦截器,_get() 访问未定义的属性时被调用,_set()给未定义的属性赋值时被调用,_isset()对未定义的属性调用isset()时被调用,_unset()对未定义的属性调用unset()时被调用,_call()调用未定义的方法时被调用