用最古老的 WordPress 系统,写最现代的 PHP 代码!

我们知道 WordPress 的函数在失败的时候,是不会抛出异常的,因为 WordPress 在 PHP 4 的时候就创建了,那时候 PHP 语法结构还没有 try/catch 异常处理机制。

WP_Error 错误处理机制

取而代之,WordPress 在失败的时候,返回返回一个WP_Error对象,比如插入文章的函数 wp_insert_post ,如果文章标题,内容摘要都为空的时候,就会插入失败,会返回 WP_Error 对象。

WP_Error 对象错误对象和异常很类似,也有一个错误代码和错误信息,比如上面的错误,返回 WP_Error 对象的错误代码就是 empty_content,错误信息是:内容,标题和摘要为空。

WordPress 还提供了 is_wp_error 函数,用于判断接受到数据是不是 WP_Error 对象,这样我们在写代码的时候,就需要自己判断返回值是不是 WP_Error 对象,然后进行额外处理,举个例子,WPJAM Basic快速复制扩展功能的代码:

function wpjam_duplicate_post($post_id){
	// 获取旧文章信息,并插入新文章
	$post_arr		= get_post($post_id, ARRAY_A);
	$new_post_id	= wp_inssert_post($post_arr, $wp_error=true);

	if(is_wp_error($new_post_id)){	// 如果失败,返回错误
		return $new_post_id;
	}

	// 获取旧文章的分类信息,并将同样的分类信息设置到新的文章中
	foreach(get_object_taxonomies($post_arr['post_type']) as $taxonomy){
		$terms	= wp_get_object_terms($post_id, $taxonomy, ['fields' => 'ids']);
		$result	= wp_set_object_terms($new_post_id, $terms, $taxonomy);	

		if(is_wp_error($result)){	// 如果失败,返回错误
			return $result;
		}
	}

	// 假如还有其他操作
	$result	= other_post_function($new_post_id, $args);

	if(is_wp_error($result)){	// 如果失败,返回错误
		return $result;
	}

	return $new_post_id;	// 最后才返回复制成功的文章 ID
}

上面的代码我为了方便演示,做了一些简化,留下大致的骨架,可以看出快速复制文章有三个过程,注释里面已经写的非常清楚,下面简单说一下

  1. 获取旧文章信息,并插入新文章,如果 WP_Error 对象,则直接返回。
  2. 获取旧文章的分类信息,并将同样的分类信息设置到新的文章中,同样碰到 WP_Error 对象,则直接返回
  3. 最后假设还有其他操作,同样也要处理错误。

这样的代码给人感觉就是满屏的错误处理,非常难受。

使用 Try / Catch 异常处理机制

有没有办法优化我们的代码呢?可以把 WP_Error 对象转换成 PHP 异常继承类的对象,然后使用现代 PHP 的 Try / Catch 异常处理机制来优化。

首先创建用于处理 WP_Error 对象的异常处理类:

class WPJAM_Exception extends Exception{
	private $wp_error	= null;

	public function __construct($message, $code=0, Throwable $previous=null){
		if(is_wp_error($message)){
			$this->wp_error	= $message;

			$message	= $this->wp_error->get_error_message();
			$code		= $this->wp_error->get_error_code();
		}else{
			$this->wp_error	= new WP_Error($code, $message);
		}

		parent::__construct($message, 0, $previous);
	}

	public function get_wp_error(){
		return $this->wp_error;
	}
}

创建一个高阶函数 wpjam_try,自动将 WP_Error 对象转换成异常:

function wpjam_try($callback, ...$args){
	try{
		$result	= call_user_func_array($callback, $args);

		if(is_wp_error($result)){
			throw new WPJAM_Exception($result);
		}

		return $result;
	}catch(Exception $e){
		throw $e;
	}
}

最后我们就可以使用 wpjam_try 对上面复制文章这段代码进行改造了

function wpjam_duplicate_post($post_id){
	try{
		// 获取旧文章信息,并插入新文章
		$post_arr		= get_post($post_id, ARRAY_A);
		$new_post_id	= wpjam_try('wp_inssert_post', $post_arr, $wp_error=true);

		// 获取旧文章的分类信息,并将同样的分类信息设置到新的文章中
		foreach(get_object_taxonomies($post_arr['post_type']) as $taxonomy){
			$terms	= wp_get_object_terms($post_id, $taxonomy, ['fields' => 'ids']);
			$result	= wpjam_try('wp_set_object_terms', $new_post_id, $terms, $taxonomy);	
		}

		// 假如还有其他操作
		$result	= wpjam_try('other_post_function', $new_post_id, $args);

		return $new_post_id;	// 最后才返回复制成功的文章 ID
	}catch(WPJAM_Exception $e){
		if($exception){
			throw $e;
		}else{
			return $e->get_wp_error();
		}
	}
}

改造的过程分成三步:

  1. 把会返回 WP_Error 对象的函数,通过 wpjam_try 调用。
  2. 去掉所有 is_wp_error 的判断,因为 wpjam_try 会抛出异常。
  3. 将所有代码放到 try/catch 的结构中,最后只需要捕捉异常,再将异常转换成 WP_Error 对象即可。

这样就可以在 WordPress 写代码的时候,避免满屏幕的错误处理,最后返回还是 WP_Error 对象,保证了对原来逻辑的兼容。


©我爱水煮鱼,本站推荐使用的主机:阿里云,国外主机建议使用BlueHost

本站长期承接 WordPress 优化建站业务,请联系微信:「chenduopapa」。