本系列的第二部分著重於編寫 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
变量。 (注意:如果该方法被声明为静态,那么您可以解决这个问题)。
当然,面向对象编程有其优点,如第一部分所述。正如 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>'; }
希望这两篇文章有助于突出这些编程风格的优点和缺点。要点是,这里没有对与错,每个程序员都有自己的个人偏好。但某些上下文更容易适应某种编程风格 - 因此您应该期望您的插件包含两者的混合。
以上是探索函數式程式設計:開發 WordPress 外掛的途徑的詳細內容。更多資訊請關注PHP中文網其他相關文章!