你的问题并不是关于WordPress,而是关于PHP和重构。但我们在这里看到了太多糟糕的代码,我将在下面解释的模式(MVC)可以帮助许多其他开发人员,所以我决定写一个小答案。请记住,我们的网络中有一个专门针对此类问题的网站:Code Review. 不幸的是,很少有WordPress开发人员活跃在那里。
如何重构代码删除无用代码。美化其余部分找到所有重复的表达式并创建例程(函数或类)来抽象和封装这些表达式单独的数据处理model (存储、提取、转换、解释),从输出中view (HTML、CSV等)
1。删除无用代码。美化其余部分
输出
您有这个重复片段:
if( $query->have_posts()) : while( $query->have_posts() ) : $query->the_post();
the_post_thumbnail(\'thumbnail\');
endwhile;
endif;
你开的车很贵
the_post()
每次都可以获取帖子缩略图。但这并不需要,你可以打电话:
echo get_the_post_thumbnail( $post_id, \'post-thumbnail\' );
查询所以您只需要post ID,无需调用
the_post()
.更好的是:您可以限制查询只获取ID。
一个简单的例子:
$post_ids = array();
$args = array(
\'post_type\' => \'post\',
\'posts_per_page\' => 10,
\'fields\' => \'ids\'
);
$query = new WP_Query( $args );
if ( ! empty ( $query->posts ) )
$post_ids = $query->posts; // just the post IDs
现在您有了ID,可以编写:
foreach ( $post_ids as $post_id )
echo get_the_post_thumbnail( $post_id, \'post-thumbnail\' );
没有开销,您的代码已经更快、更容易阅读了。
语法请注意我是如何对齐=
? 这有助于理解代码,因为人脑擅长于模式识别。支持这一点,我们就能做一些了不起的事情。制造混乱,我们很快就会陷入困境。
这也是我删除的原因endwhile
和endif
. 这个alternative
syntax 杂乱无章,难以阅读。另外,它使working in an IDE 难度更大:用大括号从表达式的开头到结尾折叠和跳跃更容易。
默认值$args
数组中的某些字段随处可见。创建一个默认数组,只写一次这些字段:
$args = array(
\'post_type\' => \'product\',
\'posts_per_page\' => 100,
\'fields\' => \'ids\',
\'tax_query\' => array(
array(
\'taxonomy\' => \'product_cat\',
\'field\' => \'slug\',
)
)
);
再次注意对齐。还要注意我是如何改变
posts_per_page
价值
Never ask for -1
. 当有一百万个匹配的帖子时会发生什么?您不想每次运行此查询时都终止数据库连接,是吗?谁应该读这些帖子?始终设定合理的限制。
现在你只需要改变场地$args[ \'tax_query\' ][ \'terms\' ]
. 我们稍后将讨论这个问题。
2。找到所有重复的表达式并创建例程,我们已经清理了一些重复代码,现在是最困难的部分:post参数的计算。显然,您已经根据一些参数制作了一些标签。我建议将它们重命名为更容易理解的名称,但现在我们将使用您的命名方案。
将这些组与其余组分开,创建一个以后可以单独管理的阵列:
$groups = array(
\'fashion-follower\' => array(
\'q1\' => \'party\',
\'q2\' => \'clothes\',
\'q3\' => \'shopping\',
\'q4\' => FALSE,
\'q5\' => \'sunbathing\',
\'q6\' => \'mini\',
),
\'the-homemaker\' => array(
\'q1\' => \'drink\',
\'q2\' => \'candles\',
\'q3\' => \'house\',
\'q4\' => \'diy\',
\'q5\' => FALSE,
\'q6\' => FALSE,
)
);
填补缺失
terms
在默认数组中,运行
$groups
数组,直到找到匹配项:
function get_query_term( $groups )
{
foreach ( $groups as $term => $values )
{
if ( compare_group_values( $values ) )
return $term;
}
return FALSE;
}
function compare_group_values( $values )
{
foreach ( $values as $key => $value )
{
// Key not sent, but required
if ( empty ( $_POST[ $key ] ) and ! empty ( $value ) )
return FALSE;
// Key sent, but wrong value
if ( ! empty ( $_POST[ $key ] ) and $_POST[ $key ] !== $value )
return FALSE;
}
// all keys matched the required values
return TRUE;
}
我甚至将术语列表的运行和值的比较分开,因为这是不同的操作。代码的每一部分都应该只做一件事,并且必须保持缩进水平以提高可读性。
现在我们有了所有的部件,让我们把它们粘在一起。
3。组织:将模型从视图中分离出来当我编写模型和视图时,我想到了一件事:MVC方法。它代表Model View Controller,一种组织软件组件的著名模式。到目前为止,缺少的部分是控制器,我们稍后将看到如何使用它。
您说过,您对PHP了解不多,所以我希望您对输出了解更多。:)让我们从这个开始:
class Thumbnail_List
{
protected $source;
public function set_source( Post_Collector_Interface $source )
{
$this->source = $source;
}
public function render()
{
$post_ids = $this->source->get_post_ids();
if ( empty ( $post_ids ) or ! is_array( $post_ids ) )
return print \'Nothing found\';
foreach ( $post_ids as $post_id )
echo get_the_post_thumbnail( $post_id, \'post-thumbnail\' );
}
}
简单明了:我们有两种方法:一种是设置帖子ID的源代码,另一种是渲染缩略图。
你可能想知道这是什么Post_Collector_Interface
是我们马上就要开始了。
现在是我们观点的来源,模型。
class Post_Collector implements Post_Collector_Interface
{
protected $groups = array();
public function set_groups( Array $groups )
{
$this->groups = $groups;
}
public function get_post_ids()
{
$term = $this->get_query_term();
if ( ! $term )
return array();
return $this->query( $term );
}
protected function query( $term )
{
$args = array(
\'post_type\' => \'product\',
\'posts_per_page\' => 100,
\'fields\' => \'ids\',
\'tax_query\' => array(
array(
\'taxonomy\' => \'product_cat\',
\'field\' => \'slug\',
\'terms\' => $term
)
)
);
$query = new WP_Query( $args );
if ( empty ( $query->posts ) )
return array();
return $query->posts;
}
protected function get_query_term()
{
foreach ( $this->groups as $term => $values )
{
if ( compare_group_values( $values ) )
return $term;
}
return FALSE;
}
protected function compare_group_values( $values )
{
foreach ( $values as $key => $value )
{
// Key not sent, but required
if ( empty ( $_POST[ $key ] ) and ! empty ( $value ) )
return FALSE;
// Kent sent, but wrong value
if ( ! empty ( $_POST[ $key ] ) and $_POST[ $key ] !== $value )
return FALSE;
}
// all keys matched the required values
return TRUE;
}
}
这已经不是那么微不足道了,但我们已经拥有了大部分的部分。这个
protected
方法(函数)无法从外部访问,因为我们只需要用于内部逻辑。
这个public
方法很简单:首先得到$group
数组,第二个返回一个post id数组。我们再次遇到这个可疑的Post_Collector_Interface
.
接口是合同。它可以由类签名(实现)。需要一个接口,就像我们的类Thumbnail_List
does,意味着:该类需要使用这些公共方法的其他类。
让我们构建该接口。其实很简单:
interface Post_Collector_Interface
{
public function set_groups( Array $groups );
public function get_post_ids();
}
是的,仅此而已。代码很简单,不是吗?
我们在这里所做的:我们提出了我们的观点Thumbnail_List
独立于一个具体类,而我们仍然可以依赖于我们得到的类的方法$source
.如果以后改变主意,可以编写一个新类来获取post ID或使用具有固定值的类。只要实现了该界面,视图就会得到满足。现在甚至可以使用模拟对象测试视图:
class Mock_Post_Collector implements Post_Collector_Interface
{
public function set_groups( Array $groups ) {}
public function get_post_ids()
{
return array ( 1 );
}
}
这在您需要时非常有用
test 视图。您不想同时测试这两个混凝土类,因为您看不到错误的来源。模拟对象对于错误来说过于简单,非常适合单元测试。
现在我们必须以某种方式组合我们的课程。这是控制器进入阶段的地方。
class Thumbnail_Controller
{
protected $groups = array(
\'fashion-follower\' => array(
\'q1\' => \'party\',
\'q2\' => \'clothes\',
\'q3\' => \'shopping\',
\'q4\' => FALSE,
\'q5\' => \'sunbathing\',
\'q6\' => \'mini\',
),
\'the-homemaker\' => array(
\'q1\' => \'drink\',
\'q2\' => \'candles\',
\'q3\' => \'house\',
\'q4\' => \'diy\',
\'q5\' => FALSE,
\'q6\' => FALSE,
)
);
public function __construct()
{
// not a post request
if ( \'POST\' !== $_SERVER[ \'REQUEST_METHOD\' ] )
return;
// set up the model
$model = new Post_Collector;
$model->set_groups( $this->groups );
// prepare the view
$view = new Thumbnail_List;
$view->set_source( $model );
// finally render the tumbnails
$view->render();
}
}
控制器是应用程序的唯一部分;模型和视图可能会到处重复使用,甚至在完全不同的部分。但是控制器的存在只是为了这个目的,这就是为什么我们把
$group
在这里
现在你只需要做一件事:
// Let the dogs out!
new Thumbnail_Controller;
在需要输出的任何地方调用此行。
您可以在下面的中找到此答案中的所有代码gist on GitHub.