Ускоряем разработку на PHP с помощью перегрузки

от автора

Проблема

Часто приходится писать так (примеры кода на Yii, но подход можно применить к любому коду):

$model = new User(); $model->name = 'Вася'; if (!$model->save())     throw new RuntimeException('Can not save!'); 

Или так:

$model = User::model()->find(); if (!$model)     throw new CHttpException(404, 'User not found!'); 

Кеширование:

$dependency = new \caching\TagDependency('Post'); $posts = Post::model()->cache(1000, $dependency)->findAll(); 

Транзакции:

$trx = $this->getDbConnection()->beginTransaction(); try {     if (!$user->makePayment())         throw new \RuntimeException('Can not complete!');      $trx->commit(); } catch (\Exception $e) {     $trx->rollback();      throw $e; } 

Слишком много кода!

Решение

Вышеприведенные куски кода можно сократить до:
Возбуждаем исключение в случае неудачного результата:

$model->saveException(); User::model()->findException(); Post::model()->findAllCached(); 

Оборачиваем метод в транзакцию:

$user->makePaymentTrx(); 

Также возможны комбинации:

User::model()->findTrxCached() 

Как это реализовать?

На Yii создаем свой класс ActiveRecord и наследуем от него свои модели:

class ActiveRecord extends CActiveRecord { 	public function __call($name, $args) 	{ 		if (preg_match('/^(.+)(cached|exception|trx)$/i', $name, $matches)) { 			switch (strtolower($matches[2])) { 				case 'cached': 					return $this->cachedMethod($matches[1], $args); 				case 'exception': 					return $this->exceptionMethod($matches[1], $args); 				case 'trx': 					return $this->trxMethod($matches[1], $args); 			} 			 		}  		return parent::__call($name, $args); 	}  	public function trxMethod($method, $args) 	{ 		$trx = $this->getDbConnection()->beginTransaction(); 		try { 			$value = call_user_func_array(array($this, $method), $args);  			$trx->commit(); 		} catch (\Exception $e) { 			$trx->rollback();  			throw $e; 		}  		return $value; 	}  	public function exceptionMethod($method, $args) 	{	 		$value = call_user_func_array(array($this, $method), $args); 		 		if (!$value) 			throw new Exception('False result!'); 		 		return $value; 	} 	 	public function cachedMethod($method, $args) 	{ 		$key = get_class($this) . $method . serialize($this->getPrimaryKey()) .  serialize($args) . serialize($this->getDbCriteria()); 		$key = md5($key);  		$value = \Yii::app()->cache->get($key);  		if ($value === false) { 			$value = call_user_func_array(array($this, $method), $args); 			\Yii::app()->cache->set($key, $value, 0, new \caching\TagDependency(get_class($this))); 		} else { 			//reset scope as in find*() methods 			$this->resetScope(); 		}  		return $value; 	} } 

Основа метода — регулярное выражение:

preg_match('/^(.+)(cached|exception|trx)$/i', $name, $matches) 

Вы можете добавить сюда свои суффиксы.

Преимущества:

  • Рутинные операции занимают гораздо меньше места в коде.
  • Быстрее и проще писать код.

Недостатки:

  • IDE не видит такие методы или их надо прописывать вручную, что не очень удобно.

ссылка на оригинал статьи http://habrahabr.ru/post/218471/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *