`
achun
  • 浏览: 306480 次
  • 性别: Icon_minigender_1
  • 来自: 河南郑州
社区版块
存档分类
最新评论

PHP Chain 链式编程的应用之错误处理

    博客分类:
  • PHP
阅读更多


链式编程使用起来非常惬意,本文尝试在PHP下实现一种链式编程的应用
我们知道在new class后调用method,在常规PHP编程下每次调用都要

$instance->method1();
$instance->method1();



这样无尽的写N多,如果中间有错误判断那就成这样了

if($instance->method1())
if($instance->method2())
$instance->method3();
//or
$instance->method1();
if($instance->hasError()) die('error');
$instance->method2();
if(....) ...;


看上去很烦,写起来更烦,特别是在开发期,那简直是噩梦。
如果能保证这样执行

if($instance->m0()->m1()->m2()->hasError()) die('error');


那就安逸了,实现这个,方法其实很简单就是在这种可以链式进行的方法中包含错误判断,无论如何都返回this, 当然类似hasError这样的方法是不返回this的,这一类方法总是出现在最后,但是在开发期,我们在方法里面复制粘贴N多的

if($this->hasError())
  return $this
//someting..
return $this;



这样也够烦人的,当然如果定型了,那嵌入这些代码也无所谓。开发期就烦死人了。
可以利用PHP的魔术方法来实现这个,这里给出一个基本的结构

class CChain{
	private $instance=null;
	private $haserror=false;
	public function __construct($instance) {
		if(!method_exists($instance,'getError'))
			die('Instance does not have a method getError().');
		$this->instance=$instance;
	}
	public function __call($m,$a) {
		if($this->haserror)
			return $m=='getError'?$this->haserror:$this;
		$this->haserror=&$this->instance->getError()?:false;
		if($this->haserror)
			return $m=='getError'?$this->haserror:$this;
		$ret=&call_user_func_array(array(&$this->instance, $m),$a);
		$this->haserror=&$this->instance->getError()?:false;
		if($this->haserror)
			return $m=='getError'?$this->haserror:$this;
		if($m=='getError') return $this->haserror;
		if($ret===null)
			return $this;
		return $ret;
	}
	public function __get($n) {
		return $this->instance->$n;
	}
	public function __set($n,$v) {
		$this->instance->$n=$v;
	}
}
class test {
	public $error=false;
	public function getError() {
		return $this->error;
	}
	public function setError($v) {
		$this->error=$v;
	}
	public function m0() {
		/* someting without return*/
	}
	public function m1() {
		/* someting without return*/
	}
	public function m2($foo=null) {
		if($foo) {
			return $this->setError('error '.__METHOD__);
		}
		/* someting without return*/
	}
}
$test=new CChain(new test);
print_r( $test->m0()->m1()->m2(1) );
echo($test->error);



当然如果想更详细的跟踪错误发生在那个method也很容易,改造__call记录下$m就好了。


 

0
0
分享到:
评论
6 楼 achun 2011-06-16  
yeaha 写道
搞复杂了,method()如果没错就返回$this,否则抛出异常,外面在合适的地方搞一个try{} catch {}完事

想明白了,我确实把问题搞复杂了
Exception就是用来必须被捕获的,这是一种安全措施
我的想法会产生新的问题,并不能解决根本问题,成本并没有减少,甚至增加了不安全性
5 楼 achun 2011-06-16  
yeaha 写道
每个不同的method其实都可能从属不同的类,每个method抛出不同的Exception其实也可以达到对不同的步骤出现的错误做针对性处理的目的

try {
    $obj->m1()->m2()->m3()->...;
} catch (FooException $ex) {
    // 从m1()抛出
} catch (BarException $ex) {
    // 从m2()或者m3()抛出

   $code = $ex->getCode();

   if ($code == 401) {
  
   } elseif ($code == 403) {

   }
}

你说的也很有道理,我之所以有这样的想法,出发点是
1.不想写那么多的try,想达到无try的地步
2.引入try,就要求对Exception做统一的规划
  这本来没什么错的,OOP的设计都这样要求
  可是我想做基于lib组装成框架的设计,因此要求lib都是自完备的
  也就是说我对于现在很多的框架的灵活性不是很认同,一旦用了一个框架
  就被框住了

我试图通过一些手段解除这个框。
到底这个想法是否符合真是代码环境,我运用到实际当中尝试下
4 楼 yeaha 2011-06-14  
每个不同的method其实都可能从属不同的类,每个method抛出不同的Exception其实也可以达到对不同的步骤出现的错误做针对性处理的目的

try {
    $obj->m1()->m2()->m3()->...;
} catch (FooException $ex) {
    // 从m1()抛出
} catch (BarException $ex) {
    // 从m2()或者m3()抛出

   $code = $ex->getCode();

   if ($code == 401) {
  
   } elseif ($code == 403) {

   }
}
3 楼 yeaha 2011-06-14  
如果要关心到链的中间被打断,自行做后续处理,还不如把可能被打断的地方分为两块

fn1 {
    method1();
    method2();
    return ...;
}

fn2 {
    method3();
    method4();
}

if (fn1()) {
    fn2();
} else {
    // if error
}

可读性也会好很多

try {
    $obj->m1()->m2()->m3()->...;
} catch (Exception $ex) {
}

这是两种业务流程,按需组织就得了,不需要专门去搞“精巧”的机制,读代码的人需要理解你的代码的前提条件越少越容易懂

而且你那个写法里面有一些所谓的getError这样的硬编码,用这种机制就非得写getError(),无端产生了一条约束,底层架构约束越少,依赖越少,越灵活
2 楼 achun 2011-06-14  
yeaha 写道
搞复杂了,method()如果没错就返回$this,否则抛出异常,外面在合适的地方搞一个try{} catch {}完事

try是解决问题的一种方法
但是try要放到那里呢?
是全局做一个还是,需要的地方都inline部署?
做全局灵活性没有了,而且try会打断程序流,也许被打断的后面还有相应的处理
inline部署,那要写多少啊?
用这种错误chain的话就成这种情况了
if(false===$ret=obj->m1()-m2->m3->mn()){
  error(....)
}
1 楼 yeaha 2011-06-14  
搞复杂了,method()如果没错就返回$this,否则抛出异常,外面在合适的地方搞一个try{} catch {}完事

相关推荐

Global site tag (gtag.js) - Google Analytics