卓越飞翔博客卓越飞翔博客

卓越飞翔 - 您值得收藏的技术分享站
技术文章16789本站已运行3321

探索函数式编程:开发 WordPress 插件的途径

探索函数式编程:开发 WordPress 插件的途径

本系列的第二部分着眼于编写 WordPress 插件时可以使用的两种不同的编程风格(有时称为编程范例)。在第一部分中,Tom McFarlin 介绍了面向对象编程。在这一部分中,我们将讨论函数式编程。

由于读者的经验水平各不相同,我们将讨论高级编程,因此如果您是初学者,那么您应该没有问题。但是,如果您是一位经验丰富的开发人员,那么您可能会在本文后面找到更多有用的信息。


什么是函数式编程?

函数式编程可能是您最熟悉的风格,而且几乎是普遍使用的风格,也是互联网上各种 WordPress 代码片段网站所使用的风格。因此,它有时可以被视为“入门级”编程:初学者在学会掌握面向对象编程之前所采用的风格。这是令人难以置信的误导,因为虽然函数式编程要简单得多,但它本身并不逊色。

函数式编程强调对函数的评估,并避免使用状态或对象的概念,这与面向对象编程相反,面向对象编程鼓励将代码视为作用于对象,使用方法来更改这些对象或与它们交互。让我们看一个非常简单的示例来比较这两种样式:


	// Functional method
	function add_two( $n ) {
		return $n +2;
	}

	$a = 2;
	$b = add_two( $a ); // $b = 4;


	// Object oriented method
	class Number {
		var $value = 0;

		function __construct( $a ) {
			$this->value = $a;
		}

		function add_two() {
			$this->value = $this->value +2;
		}
	}

	$a = new Number( 2 );
	echo $a->value; //Prints 2
	$a->add_two();
	echo $a->value; //Prints 4

这个非常简单的示例说明了两种范式风格上的根本区别:函数式编程侧重于向函数传递参数以及从函数接收值。没有被作用的“对象”,只有参数和返回值。相反,面向对象的方法为对象分配各种属性(在我们的例子中为“值”),并且方法对这些属性起作用。


函数:基础知识

定义函数非常简单:


	function add( $number, $number2 = 1 ) {
		// Perform code acting on passed variables
		$sum = $number + $number2;

		// Optional, if needed you can return a value
		return $sum;
	}

声明函数后,它可以在插件中的任何位置使用 - 换句话说,它具有全局作用域。


	$a = 4;
	$b = 7;
	echo add( $a, $b ); // Prints 11
函数必须有唯一的名称。重新声明函数会引发错误。由于您的代码将与其他插件、主题和 WordPress 本身一起运行,因此您永远不应该使用通用名称。相反,您应该在函数名称前添加一些唯一的前缀(例如插件的名称)。

您可能已经注意到,在 add 的定义中,第二个参数设置为等于 1。这为 $number2 设置默认值(在本例中为 1),这样就使参数成为可选的。如果未提供参数,则该值将被视为默认值:


	echo add( 4 ); // Prints 5
	echo add( 4, 1 ); // Prints 5

另一方面,没有为第一个值提供默认值,因此省略该参数将引发错误


	echo add(); // Throws an error as $number is not defined

您还可以拥有可变数量的参数。在函数内部,我们可以使用 func_num_args() 来获取收到的参数数量,而 func_get_arg() 允许您访问特定的传递变量,索引从 0 开始。


function sum() {
	// Get the number of arguments given to sum()
	$number_args = func_num_args();

	$sum = 0;

	if ( ! $number_args )
		return $sum;

	for ( $i = 0; $i < $number_args; $i++ ) {
		$sum += func_get_arg( $i );
	}

	return $sum;
}

echo sum( 1, 2,  3, 4 ); //Prints 10
echo sum( 1, 2 ); //Prints 3
echo sum(); //Prints 0

上面的内容也可以用在对象方法中。最后,通过将变量声明为“全局”,您可以从函数内部访问该变量。


	$a = \'Hello\';
	$b = \'World\';
	function hello_world() {
		// This is necessary to access $a and $b 
		// declared outside of the function scope.
		global $a, $b;
		$b = $a . \' \' . $b;
	}
	hello_world();
	echo $b; // Prints \'Hello World\'
通常不鼓励使用全局变量。特别是因为两个插件对全局变量使用相同的名称可能会导致一个或两个插件损坏。如果您必须使用全局变量,请再次通过添加插件名称作为前缀来确保其唯一。

为什么使用函数式编程?

决定使用哪种编程风格取决于判断 - 是的 - 个人喜好。使用函数式编程而不是面向对象编程并没有更正确或更错误的说法,但通常情况下,有一种风格更适合您想要实现的目标。

有时面向对象编程根本没有必要,只会使事情变得过于复杂,或者引入多余的代码。一个例子可能是 WordPress 提供的各种“实用”功能。这些是用于执行特定目的的通用函数。例如 wp_trim_words( $text, $num_words ) 只是将给定的字符串修剪到一定的大小(以单词为单位)。它不会添加任何内容来将 wp_trim_words() 定义为属于某个对象的方法,并且会导致更丑陋的代码。对于函数式编程,只需一行。

函数式编程的一个优点是它的简单性,特别是对于初学者来说。您不必担心静态、私有或受保护的函数 - 它们都是全局的。静态变量的概念也不存在。在最基本的层面上,你的函数返回一个从你给它的内容派生的输出。例如, get_the_title( 7 ) 将返回 ID 为 7 的帖子的标题。

函数式编程的另一个优点是函数可以全局访问。对于面向对象的程序,为了对特定对象进行操作,您需要传递该对象。这有时可能很棘手。为了说明这一点,让我们以第一部分中的示例为例:


class DemoPlugin {
	public function __construct() {
		add_action( \'wp_enqueue_scripts\', array( $this, \'register_plugin_scripts\' ) );
	}

	public function register_plugin_scripts() {
		// Register plugin scripts
	}
}
$demo_plugin = new DemoPlugin();

当 WordPress 存储 register_plugin_scripts() 方法时,以便在触发 wp_enqueue_scripts 操作时调用它,它不仅通过引用该方法,而且还引用对象 $demo_plugin 来实现此目的。这是因为同一对象的不同实例的相同方法被视为不同的方法 - 即 $demo_plugin->register_plugin_scripts()$copy_of_demo_plugin->register_plugin_scripts() 不是相同。这可能看起来很奇怪 - 但对于同一类的不同实例,方法的行为可能不同,因此我们需要引用方法和实例。

但是为什么这很重要呢?这使得第三方插件或主题很难取消该方法,因为为此他们需要调用:


	remove_action( \'wp_enqueue_scripts\', array( $demo_plugin, \'register_plugin_scripts\' ) );

但通常他们无法访问 $demo_plugin 变量。 (注意:如果该方法被声明为静态,那么您可以解决这个问题)。


WordPress 中的面向对象和函数式编程

当然,面向对象编程有其优点,如第一部分所述。正如 Tom 还提到的,使用 WordPress 的小部件 API 时这是不可避免的。另一个常见的例子是 WP_Query()。在这里,面向对象的方法显然是最好的:您有一个对象(在本例中是一个查询),它具有各种属性(即搜索条件、分页信息、匹配结果),并且您想要对该查询进行操作(解析它,生成并清理相应的SQL,并返回结果)。

WP_Query() 演示了正确使用时面向对象编程的强大功能。发起查询后:


$the_query = new WP_Query( array(...) );

您不仅可以访问结果,还可以访问其他信息,例如分页值:有多少页结果、正在查看哪个页面、结果总数以及查询的“类型”,例如$the_query->is_search()$the_query->is_single() 等。还有整个“循环”基础设施;


	if ( $the_query->have_posts() ) {
		echo \'<ul>\';
		while( $the_query->have_posts() ): $the_query->the_post();
			// The Loop
			echo \'<li>\' . get_the_title( $the_post->ID ) . \'</li>\';
		endwhile;
		echo \'</ul>\';
	}
	wp_reset_postdata();

它将结果和全局变量的所有内部处理隐藏在人性化的 API 后面。

那么 get_posts() 呢?这只是作为 WP_Query() 的包装器,并简单地返回与查询匹配的帖子数组。因此,您不会得到 WP_Query() 的“花哨”功能,但它的效率稍高一些。因此,是否应该使用 get_posts() 还是 WP_Query() 取决于您的用例(例如,是否需要分页),但这也取决于个人喜好。


	$results = get_posts( array( ... ) );

	if ( $results ) {
		echo \'<ul>\';
		foreach( $results as $the_post ) {
			echo \'<li>\' . get_the_title( $the_post->ID ) . \'</li>\';
		}
		echo \'</ul>\';
	}

摘要

希望这两篇文章有助于突出这些编程风格的优点和缺点。要点是,这里没有对与错,每个程序员都有自己的个人偏好。但某些上下文更容易适应某种编程风格 - 因此您应该期望您的插件包含两者的混合。

卓越飞翔博客
上一篇: 在 C# 中使用哈希表和字典
下一篇: 返回列表
留言与评论(共有 0 条评论)
   
验证码:
隐藏边栏