PHP面向物件的一些坑爹技巧
最近在肝PHP和Mysql
以我學了四天PHP的感覺來看
PHP的類如果不是考慮前後端徹底分離的話,用class來封裝整個網頁的Page用來重複利用還是不錯的
然後在學習面向物件的時候有些坑爹(高深)的操作讓我有些苦惱
1.迭代屬性
<?php class myClass { public $a="xiao"; public $b="yu"; public $c="yu"; } $x=new myClass; foreach ($x as $key ) { echo $key."<br />"; } echo "<br />"; ?>
上面這段程式碼還是很簡單的,就是用foreach輸出類中的所有屬性,然後開始玄學,迭代器……
2.迭代器
為什麼要用迭代器呢,如果我們的迭代行為很複雜,用迭代器是不錯的操作
然後重點來了迭代器(iterator)需要IteratorAggregate介面,getIterator(返回該迭代器例項)
生命一個類有迭代器介面的方法:
class ObjectIterator implements Iterator //生命ObjectIterator是一個迭代器,可以呼叫迭代器介面所要求的一系列函式
有哪些函式是需要的呢,如下(不需要解構函式)
class ObjectIterator implements Iterator //生命ObjectIterator是一個迭代器,可以呼叫迭代器介面所要求的一系列函式 { private $obj; private $count; private $currentIndex; //建構函式 function __construct($obj) { $this->obj=$obj; $this->count=count($this->obj->data); } //重置內部資料指標 function rewind() { $this->currentIndex=0; } //判斷資料指標當前位置是否還存在更多資料 function vaild() { return $this->currentIndex<$this->count; //true即為vaild } //返回資料指標值 function key() { return $this->currentIndex; } //返回當前資料指標指向的資料 function current() { return $this->obj->data[$this->currentIndex]; } //向後移動資料指標1step function next() { $this->currentIndex++; } }
其實就是要把foreach的操作封裝在類裡面來應付各種各樣的情況,乍一看比較多此一舉,但是實際應用還是有價值的,不同的迭代方式我們用這些操作基本都可以搞定
這只是迭代器,我們還需要迭代器的介面IteratorAggregate,我們上面用的data就是接口裡的變數,通過這個介面把需要迭代的變數傳給迭代器運作(通過getIterator)
class Object implements IteratorAggregate { public $data=array(); function __construct($in) { $this->data=$in; } function getIterator() { return new ObjectIterator($this); } }
分解開來慢慢分析其實還可以,就是把變數傳進data,在把變數的指標傳給迭代器,從而進行運作
給個例子
<?php
class ObjectIterator implements Iterator //生命ObjectIterator是一個迭代器,可以呼叫迭代器介面所要求的一系列函式
{
private $obj;
private $count;
private $currentIndex;
//建構函式
function __construct($obj)
{
$this->obj=$obj;
$this->count=count($this->obj->data);
}
//重置內部資料指標
function rewind()
{
$this->currentIndex=0;
}
//判斷資料指標當前位置是否還存在更多資料
function valid()
{
return $this->currentIndex<$this->count; //true即為vaild
}
//返回資料指標值
function key()
{
return $this->currentIndex;
}
//返回當前資料指標指向的資料
function current()
{
return $this->obj->data[$this->currentIndex];
}
//向後移動資料指標1step
function next()
{
$this->currentIndex++;
}
}
class Object implements IteratorAggregate
{
public $data=array();
function __construct($in)
{
$this->data=$in;
}
function getIterator()
{
return new ObjectIterator($this);
}
}
$myObject=new Object(array(2,4,6,8,10)); //data改為一個array
$myIterator= $myObject->getIterator(); //data的地址傳入迭代器
for($myIterator->rewind();$myIterator->valid();$myIterator->next())
{
$key=$myIterator->key();
$value=$myIterator->current();
echo $key."=>".$value."<br />";
}
echo "<br />";
?>
結果如下
這個其實還比較容易,但是如果複雜了呢,或者是用了別的迭代方式麼,不論內部實現怎麼變化,資料介面都是固定的,不用我們多費心,這就是迭代器的作用
3.生成器
生成器怎麼說了也算是在迭代中使用的,而且比迭代器簡單且容易理解,如果能用生成器的話,我個人傾向於直接while、for之類的,這裡就不做介紹了
4.反射API
這個操作有點像爬去類的結構的爬蟲?
如果我們手裡有一些類的文件,但是不熟悉,變數很複雜,很容易看的一頭霧水,這個時候這個操作就很有用了,來個例子比較直觀
<?php
class Page
{
public $content;
public $title="TLA Consulting Pty Ltd";
public $keywords="TLA Consulting, Three Letter Abbreviation, some of my best friends are search engines";
public $buttons=["Home"=>"12_home.php",
"Contact"=>"12_contact.php",
"Services"=>"12_services.php",
"Site Map"=>"12_map.php"];
//class Page's operations
public function __set($name,$value)
{
$this->$name=$value;
}
public function Display()
{
echo "<html>\n<head>\n";
$this->DisplayTitle();
$this->DisplayKeywords();
echo "</head>\n<body>\n";
$this->DisplayHeader();
$this->DisplayMenu($this->buttons);
echo $this->content;
$this->DisplayFooter();
echo "</body>\n</html>\n";
}
public function DisplayTitle()
{
echo "<title>".$this->title."</title>";
}
public function DisplayKeywords()
{
//<meta> 標籤永遠位於 head 元素內部
//元資料總是以名稱/值的形式被成對傳遞的
echo "<meta name='keywords' content='".$this->keywords."'/>";
echo "<title>".$this->title."</title>";
}
public function DisplayHeader()
{
?>
<!-- page header -->
<header>
<img src="./11.jpg" alt="TLA logo" height="200" width="600"/>
<h1>TLA Consulting</h1>
</header>
<?php
}
public function DisplayMenu($buttons)
{
echo "<!--menu-->
<nav>";
while(list($name,$url)=each($buttons))
{
$this->DisplayButton($name,$url,!$this->IsURLCurrentPage($url));
}
echo "</nav>\n";
}
public function IsURLCurrentPage($url)
{
//例如,在地址為 http://example.com/foo/bar.php 的指令碼中使用 $_SERVER['PHP_SELF'] 將得到 /foo/bar.php
if(strpos($_SERVER['PHP_SELF'],$url)===false)
{
return false;
}
else
{
return true;
}
}
public function DisplayButton($name,$url,$active=true)
{
if($active)
{
?>
<div class="menuitem">
<a href="<?=$url?>">
<img src="./1.jpg" alt="" height="50" width="50"/>
<!-- ?=?可以在html中表示php的屬性值 -->
<span class="menutext"><?=$name?></span>
</a>
</div>
<?php
}
else
{
?>
<div class="menuitem">
<img src="./1.jpg" alt="" height="50" width="50"/>
<span class="menutext"><?=$name?></span>
</div>
<?php
}
}
public function DisplayFooter()
{
?>
<!-- page footer -->
<footer style="background: #ccccff;">
<p>TLA Consulting Pty Ltd.<br />
Please see our legal information page.</p>
</footer>
<?php
}
}
?>
上面這是我們的一個類,東西還是蠻多的對於我這個菜雞來說,我們接下來用反射API來爬取
<?php
//反射API
require_once("12_page.php");
$class =new ReflectionClass("Page");
echo "<pre>".$class."</pre>";
?>
結果如下
對我這種菜鳥幫助還蠻大的,能一眼看出一個類大概的操作和結構
5.延遲靜態繫結
這是繼承裡的操作,下面這個例子的輸出可以很好地解釋
<?php
class A
{
public static function whichclass()
{
echo __CLASS__; //使用 self:: 或者 __CLASS__ 對當前類的靜態引用,取決於定義當前方法所在的類
}
public static function test()
{
self::whichclass();
}
}
class B extends A
{
public static function whichclass()
{
echo __CLASS__;
}
}
A::test();
echo "<br />";
B::test();
?>
輸出結果如下
兩個A,而不是A B
我們要解決這個問題很簡單,把self改成static就好啦,可以試一下哦
6.多重繼承?(Trait)
對不起,PHP沒有多重繼承,但是可以用別的方法實現,比如Trait,又比如介面
Trait對我來說感覺好的地方就是他強調的程式碼重用是包含了實現的,因人而異吧,介面的話比較快捷,Triat組合起來我覺得還蠻爽的
<?php
trait fileLogger
{
public function logmessage($message,$level="DEBUG")
{
//code
}
}
trait sysLogger
{
public function logmessage($message,$level="ERROR")
{
//code
}
}
class fileStorage
{
use fileLogger,sysLogger
{
fileLogger::logmessage insteadof sysLogger;
sysLogger::logmessage as logsymessage;
}
function store($data)
{
$this->logmessage($message);
$this->logsymessage($message);
}
}
?>
上述程式碼就體現Trait的組合特點,而且我們可以看到如果遇到重名的函式,可以用instead和as來輕鬆解決,這樣新的類就可以使用你所需要的Trait了,繼承不同Trait,但不是直接繼承不同的類的部分,算是一種模擬的多重繼承吧,用起來有時候有不錯的效果,而且很靈活,可是隨時給類“打補丁”