[英]PHP: Is it possible to call a public class function inside of an exception throw?
[英]Check and throw exception on every function call
我正在用PHP編寫一個函數,將給定其URL的圖像保存到本地文件。 這是我想出的:
private function retrieve_image_url($image_url, $upload_path) {
$img_data = @file_get_contents($image_url);
if ($img_data === false) {
throw new ImageRetrieverException('Invalid image source: '. $image_url);
}
$file = @fopen($upload_path, "w+");
if ($file === false) {
throw new ImageRetrieverException('Cannot open for writting: '. $upload_path);
}
if (fwrite($file, $img_data) === false) {
throw new ImageRetrieverException('Writing failed: '. $result);
}
if (fclose($file) === false) {
throw new ImageRetrieverException('Cannot close: '. $file);
}
}
您可以看到該函數看起來過於復雜/難以閱讀,因為我正在檢查每個函數調用並拋出異常。 這樣做是不好的做法嗎?
我想您只發布了方法retrieve_image_url
一部分。
讓我們談談那段代碼。
這取決於。 通常,“良好做法”是關於代碼應如何的提示,但不是強制性的。
如果您對所有代碼都遵循所有良好實踐,那么您可能會引入過度設計,而在大多數情況下則不需要。 (這是一個不好的做法,哈哈。看看YAGNI )
在將來代碼將成為高級維護(修改,刪除等)的一部分時,通常需要良好實踐。 但是,如果您的代碼永遠都是這樣,那么現在您將其埋葬,明天便會忘記它,那么可能就不需要“良好實踐”。
同樣,如果您的代碼將要與其他人(您的工作同事等)共享,則是遵循良好做法的好步驟,以使您的同事輕松理解並輕松修改代碼(如果要修改)。
乍一看,您的代碼插入了一些循環復雜性 。
這也違反了開放/封閉原則 ,即您必須開放才能進行擴展,而不能進行修改。
為什么該方法是私有的? 當將要從類中的多個位置調用這些方法時,我經常使用私有方法。 如果僅從一個位置調用此方法,則最好內聯調用該方法的位置。
我認為,我會將您的代碼引入單元測試。
測試將提示什么是壞的,什么是好。
這聽起來很瘋狂,但是隨着時間的流逝,您將學會“聽到測試對您的代碼所說的話”。
但是首先它需要進行一些集成測試,這是一個安全網,可以確認我們的重構沒有破壞代碼。
首先,我們對所有異常情況和有效情況進行集成測試:
public class retrieveImageUrl extends PHPUnit_Framework_TestCase
{
public static function casesProvider()
{
return array(
array("bad URL", "Bad Upload PATH"), //Keep adding all the invalid cases here
array("replace here with good URL", "Bad upload PATH"), //etc etc
);
}
/**
* @expectedException ImageRetrieverException
* @dataProvider casesProvider
*/
public function testRetrieveImageThrowsInvalidImageSource($url, $path) {
$yourClass = new YourClass();
$yourClass->retrieve_image_url($url, $path);
}
public function testRetrieveImageValidCase() {
$yourClass = new YourClass();
$yourClass->retrieve_image_url("replace with good url", "replace with good path");
}
}
由於該方法是私有的,因此測試將失敗。 我們將該方法公開(這樣我們就可以對其進行測試)
public function retrieve_image_url($image_url, $upload_path) {
$img_data = @file_get_contents($image_url);
if ($img_data === false) {
throw new ImageRetrieverException('Invalid image source: '. $image_url);
}
$file = @fopen($upload_path, "w+");
if ($file === false) {
throw new ImageRetrieverException('Cannot open for writting: '. $upload_path);
}
if (fwrite($file, $img_data) === false) {
throw new ImageRetrieverException('Writing failed: '. $result);
}
if (fclose($file) === false) {
throw new ImageRetrieverException('Cannot close: '. $file);
}
}
然后,我們使用復合模式遵循開/關原則。
我們創建一個“ Validator”類,它將驗證您實際代碼中的兩個約束。
class imageValidator implements InterfaceValidator {
private $validators;
public __construct(array $validators = array()) {
$this->validators = $validators;
}
public function validate($file = null, $imgData = null) {
foreach($this->validators as $validator)
$validator->validate($file, $imgData);
}
}
我們創建的接口將成為所有驗證器的實現。
interface imageInterfaceValidator {
public function validate($file = null, $imgData = null);
}
接下來是查看驗證方法輸入的約束:
$img_data === false -> throw new ImageRetrieverException('Invalid image source: '. $image_url);
$file === false -> throw new ImageRetrieverException('Cannot open for writting: '. $upload_path);
並將每一個放入實現驗證器接口的類中。 例如,第一個驗證器將是:
class validatorImageFalse implements imageInterfaceValidator {
public function validate($file = null, $imgData = null) {
if($img_data === false) {
throw new ImageRetrieverException('Invalid image source: '. $image_url);
}
}
}
依此類推,還有其他限制。
完成代碼后,您的代碼應大致如下所示:
public function retrieve_image_url($image_url, $upload_path) {
$validatorComposite = new imageValidator(array(/** Put here all the validators classes **/));
$img_data = @file_get_contents($image_url);
$file = @fopen($upload_path, "w+");
$validatorComposite->validate($file, $imgData);
if (fwrite($file, $img_data) === false) {
throw new ImageRetrieverException('Writing failed: '. $result);
}
if (fclose($file) === false) {
throw new ImageRetrieverException('Cannot close: '. $file);
}
}
我認為這將是提高可維護性的一種方式。 因為如果將來會出現這種情況,例如,將來您需要在圖像URL中添加一個正則表達式檢查。 您只需要添加另一個驗證器。
接下來是應用控制反轉
public function retrieve_image_url($image_url, $upload_path, imageInterfaceValidator $validatorComposite) {
$img_data = @file_get_contents($image_url);
$file = @fopen($upload_path, "w+");
$validatorComposite->validate($file, $imgData);
if (fwrite($file, $img_data) === false) {
throw new ImageRetrieverException('Writing failed: '. $result);
}
if (fclose($file) === false) {
throw new ImageRetrieverException('Cannot close: '. $file);
}
}
就是這樣。 您將看到集成測試不斷通過,這非常好。
沒關系。
Symfony對於文件系統具有類似的代碼: https : //github.com/symfony/Filesystem/blob/master/Filesystem.php :)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.