溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Rust如何開發(fā)PHP擴(kuò)展

發(fā)布時間:2022-10-28 09:35:59 來源:億速云 閱讀:116 作者:iii 欄目:編程語言

本篇內(nèi)容主要講解“Rust如何開發(fā)PHP擴(kuò)展”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“Rust如何開發(fā)PHP擴(kuò)展”吧!

為什么要使用php擴(kuò)展?

優(yōu)點(diǎn):

1、php擴(kuò)展是C開發(fā)的,那速度沒得說。

2、耦合性高,它的出現(xiàn)就是用來增強(qiáng)php的。

3、安全性高,畢竟擴(kuò)展是編譯后的程序,代碼不開源。

缺點(diǎn):

1、需針對php版本及系統(tǒng)環(huán)境進(jìn)行開發(fā),那么就比較麻煩了。也就是說7.4版本的php,liunx環(huán)境下開發(fā)的擴(kuò)展,只支持該php版本及系統(tǒng)。

2、需要會C、C++,當(dāng)然本文是以rust進(jìn)行開發(fā),對C的數(shù)據(jù)類型進(jìn)行了解,對rust FFI的操作及數(shù)據(jù)類型轉(zhuǎn)換需精通。

3、調(diào)試相對麻煩。

為什么要用rust開發(fā)php擴(kuò)展?

原因很簡單,這還要說起rust的語言特性。

1、因“所有權(quán)”的特性使你的程序更安全,不會像C那樣出現(xiàn)各種“玄學(xué)BUG”。

2、擁有C一樣的性能。

3、畢竟是最受歡迎的語言,我很看好它的發(fā)展。

rust開發(fā)php擴(kuò)展流程:

當(dāng)然,rust目前是沒有專門開發(fā)php擴(kuò)展的骨架。所以我的邏輯也很簡單,利用rust開發(fā)靜態(tài)庫暴露給C【涉及FFI的了解】。我們在php官方骨架中直接引入rust靜態(tài)庫調(diào)用其方法即可。

開發(fā)環(huán)境

寶塔【CentOS 7.6】、GCC【涉及php擴(kuò)展骨架的編譯,我這里系統(tǒng)內(nèi)置就有,如果編譯擴(kuò)展報相關(guān)錯了自行安裝】、對應(yīng)php版本源碼、web環(huán)境【寶塔中安裝對應(yīng)php版本、nginx、mysql等等】

開發(fā)整體流程:

1、準(zhǔn)備寶塔

Rust如何開發(fā)PHP擴(kuò)展

Rust如何開發(fā)PHP擴(kuò)展

這里我們以開發(fā)php7.4擴(kuò)展為例。

2、下載php7.4 liunx版源碼

php官網(wǎng):PHP: Hypertext Preprocessor

Rust如何開發(fā)PHP擴(kuò)展

Rust如何開發(fā)PHP擴(kuò)展

注意!該源碼版本必須與你環(huán)境php版本完全一致?。。?/strong>

Rust如何開發(fā)PHP擴(kuò)展

下載完畢:

Rust如何開發(fā)PHP擴(kuò)展

3、上傳php源碼到寶塔

Rust如何開發(fā)PHP擴(kuò)展

/usr/phper

在usr下創(chuàng)建一個phper文件夾,然后將源碼壓縮包上傳到此處。

Rust如何開發(fā)PHP擴(kuò)展

解壓該壓縮包

Rust如何開發(fā)PHP擴(kuò)展

4、創(chuàng)建一個我們自己的擴(kuò)展

Rust如何開發(fā)PHP擴(kuò)展

/usr/phper/php-7.4.30/ext目錄下有這么一個php文件,它可以創(chuàng)建擴(kuò)展!

Rust如何開發(fā)PHP擴(kuò)展

注意設(shè)置命令行版本,因為接下來利用php命令必須是版本一致的!

Rust如何開發(fā)PHP擴(kuò)展

在剛剛的目錄下,點(diǎn)擊終端,輸入創(chuàng)建擴(kuò)展命令。

php ext_skel.php --ext 擴(kuò)展名稱

Rust如何開發(fā)PHP擴(kuò)展

Rust如何開發(fā)PHP擴(kuò)展

這里就多出了一個新的擴(kuò)展源碼文件。

Rust如何開發(fā)PHP擴(kuò)展

Rust如何開發(fā)PHP擴(kuò)展

在該目錄下點(diǎn)擊終端,輸入:

phpize

Rust如何開發(fā)PHP擴(kuò)展

Rust如何開發(fā)PHP擴(kuò)展

接著輸入:

./configure --with-php-config=/www/server/php/74/bin/php-config

注意這個參數(shù)php路徑,如果是別的版本,請自行在寶塔里安裝找到對應(yīng)版本路徑,它們都是放一起的。

Rust如何開發(fā)PHP擴(kuò)展

回車開始進(jìn)行檢查了

Rust如何開發(fā)PHP擴(kuò)展

最后輸入:

make

進(jìn)行編譯。

Rust如何開發(fā)PHP擴(kuò)展

Rust如何開發(fā)PHP擴(kuò)展

這個目錄下便是編譯出來的so擴(kuò)展最終文件了!

Rust如何開發(fā)PHP擴(kuò)展

讓我們看下默認(rèn)生成的擴(kuò)展有哪些功能

Rust如何開發(fā)PHP擴(kuò)展

查看主文件【需了解php擴(kuò)展骨架,這里以它默認(rèn)給的為例】

Rust如何開發(fā)PHP擴(kuò)展

也就是說,剛剛編譯出來的擴(kuò)展,是有這兩個函數(shù)的,咱們測試一下玩玩。

注意!每次修改主文件,都需要重新按上述命令跑一遍,否則不生效,很奇怪!

phpize
./configure --with-php-config=/www/server/php/74/bin/php-config
make

5、使用擴(kuò)展

Rust如何開發(fā)PHP擴(kuò)展

復(fù)制剛剛生成的擴(kuò)展文件到我們php環(huán)境的擴(kuò)展里

Rust如何開發(fā)PHP擴(kuò)展

Rust如何開發(fā)PHP擴(kuò)展

配置php.ini加載hello.so擴(kuò)展

Rust如何開發(fā)PHP擴(kuò)展

extension = hello.so

保存后記得重新啟動下php,否則不生效的!

Rust如何開發(fā)PHP擴(kuò)展

Rust如何開發(fā)PHP擴(kuò)展

在文件管理中點(diǎn)擊終端,輸入:

php -m

可以看到我們的擴(kuò)展在列表中了。

創(chuàng)建一個站點(diǎn),測試下擴(kuò)展中兩個函數(shù)。

Rust如何開發(fā)PHP擴(kuò)展

看好,php版本是7.4

Rust如何開發(fā)PHP擴(kuò)展

Rust如何開發(fā)PHP擴(kuò)展

訪問站點(diǎn)

Rust如何開發(fā)PHP擴(kuò)展

沒有問題哦!

當(dāng)然也可以通過命令行運(yùn)行php腳本查看結(jié)果【前提是網(wǎng)站那里php命令行版本設(shè)置的7.4】

Rust如何開發(fā)PHP擴(kuò)展

php index.php

OK!從創(chuàng)建到生成到使用擴(kuò)展的流程結(jié)束,接下來才進(jìn)入正題,開始用rust開發(fā)擴(kuò)展。

6、rust與php擴(kuò)展的整合開發(fā)

開發(fā)工具:CLion

需要rust環(huán)境與CLion中rust插件的安裝與配置,這個自行去百度,比我想象中的全!

Rust如何開發(fā)PHP擴(kuò)展

創(chuàng)建一個hello命名的庫項目

Rust如何開發(fā)PHP擴(kuò)展

我們寫兩個導(dǎo)出函數(shù),分別是加法功能和base64字符串解析功能。

Rust如何開發(fā)PHP擴(kuò)展

lib.rs

#![crate_type = "staticlib"]

extern crate libc;

//使用C類型約束
use std::ffi::{CStr, CString};
use libc::{c_char, c_int};

//add_int【參數(shù):兩個c語言的int類型】:對兩個int類型數(shù)值進(jìn)行相加
#[no_mangle]
pub extern "C" fn add_int(x:c_int, y:c_int) -> c_int{
    //兩個數(shù)相加
    return x + y;
}

//base64_decode函數(shù)【參數(shù):c語言的*char類型】:對字符串進(jìn)行base64解碼
#[no_mangle]
pub extern "C" fn base64_decode(s:*const c_char) -> *mut c_char {
    //c char類型轉(zhuǎn)&str
    let h = unsafe{CStr::from_ptr(s).to_str().unwrap()};
    //base64 解碼
    let s = base64::decode(h.to_string());
    if let Err(_s) = s {
        panic!("類型錯誤!");
    }
    let n = String::from_utf8(s.unwrap().clone()).unwrap();
    //String 轉(zhuǎn) C CString
    let a = CString::new(n.as_str()).unwrap();
    //C CString 轉(zhuǎn) C char
    //這里實屬無奈,因為rust ffi中闡述,對字符串返回只能是該字符串地址,所以需要該方法進(jìn)行返回C才能接收到!
    let r = a.into_raw();
    return r;
}

Rust如何開發(fā)PHP擴(kuò)展

Cargo.toml

[package]
name = "hello"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[lib]
name = "hello"
crate-type = ["staticlib"]

[dependencies]
libc = "*"
base64 = "0.12.1"

注意在編譯過程中涉及系統(tǒng)類型,不然在引入該靜態(tài)庫編譯擴(kuò)展可能報錯,提示不支持。

編譯64位靜態(tài)庫

rustup target add x86_64-unknown-linux-musl
cargo build --target x86_64-unknown-linux-musl --release

編譯32位靜態(tài)庫

rustup target add i686-unknown-linux-musl
cargo build --target i686-unknown-linux-musl --release

這里我們是64位系統(tǒng)。

Rust如何開發(fā)PHP擴(kuò)展

會生成一個.a文件,該文件便是liunx支持的靜態(tài)庫文件。

生成支持C語言的膠水頭文件【用于C調(diào)用該庫需要寫的函數(shù)聲明,很方便】

創(chuàng)建cbindgen.toml文件

內(nèi)容:

language = "C"

Rust如何開發(fā)PHP擴(kuò)展

安裝cbindgen,創(chuàng)建頭文件。

cargo install --force cbindgen
cbindgen --config cbindgen.toml --crate 項目名稱 --output 頭文件名稱.h

Rust如何開發(fā)PHP擴(kuò)展

Rust如何開發(fā)PHP擴(kuò)展

自動生成了C語言的函數(shù)聲明hello.h文件,用于調(diào)用。

Rust如何開發(fā)PHP擴(kuò)展

回到之前我們創(chuàng)建的hello擴(kuò)展

創(chuàng)建lib文件夾

Rust如何開發(fā)PHP擴(kuò)展

將剛剛編譯出來的靜態(tài)庫.a文件上傳到lib目錄下

Rust如何開發(fā)PHP擴(kuò)展

將剛剛創(chuàng)建的.h頭文件上傳到擴(kuò)展目錄下

Rust如何開發(fā)PHP擴(kuò)展

配置.m4預(yù)編譯文件【關(guān)鍵】

Rust如何開發(fā)PHP擴(kuò)展

設(shè)置引入lib文件夾中的靜態(tài)庫文件Rust如何開發(fā)PHP擴(kuò)展

  PHP_ADD_LIBRARY_WITH_PATH(hello, /usr/phper/php-7.4.30/ext/hello/lib, HELLO_SHARED_LIBADD)
  PHP_SUBST(HELLO_SHARED_LIBADD)

Rust如何開發(fā)PHP擴(kuò)展

保存.m4

Rust如何開發(fā)PHP擴(kuò)展

編寫主文件

Rust如何開發(fā)PHP擴(kuò)展

/* hello extension for PHP */

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include "php.h"
#include "ext/standard/info.h"
#include "php_hello.h"
#include "hello.h"//引入頭文件
/* For compatibility with older PHP versions */
#ifndef ZEND_PARSE_PARAMETERS_NONE
#define ZEND_PARSE_PARAMETERS_NONE() \
	ZEND_PARSE_PARAMETERS_START(0, 0) \
	ZEND_PARSE_PARAMETERS_END()
#endif

/* {{{ void hello_test1()
 */
PHP_FUNCTION(hello_test1)
{
	ZEND_PARSE_PARAMETERS_NONE();

    int num = add_int(1,2);//rust中兩個數(shù)相加函數(shù)并返回。
    
	php_printf("The extension %d is loaded and working!\r\n", num);
}
/* }}} */

/* {{{ string hello_test2( [ string $var ] )
 */
PHP_FUNCTION(hello_test2)
{
	char *var = "World";
	size_t var_len = sizeof("World") - 1;
	zend_string *retval;

	ZEND_PARSE_PARAMETERS_START(0, 1)
		Z_PARAM_OPTIONAL
		Z_PARAM_STRING(var, var_len)
	ZEND_PARSE_PARAMETERS_END();

    char *newstr = base64_decode(var);//rust中解析base64字符串并返回。
    
	retval = strpprintf(0, "Hello %s", newstr);

	RETURN_STR(retval);
}
/* }}}*/

/* {{{ PHP_RINIT_FUNCTION
 */
PHP_RINIT_FUNCTION(hello)
{
#if defined(ZTS) && defined(COMPILE_DL_HELLO)
	ZEND_TSRMLS_CACHE_UPDATE();
#endif

	return SUCCESS;
}
/* }}} */

/* {{{ PHP_MINFO_FUNCTION
 */
PHP_MINFO_FUNCTION(hello)
{
	php_info_print_table_start();
	php_info_print_table_header(2, "hello support", "enabled");
	php_info_print_table_end();
}
/* }}} */

/* {{{ arginfo
 */
ZEND_BEGIN_ARG_INFO(arginfo_hello_test1, 0)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO(arginfo_hello_test2, 0)
	ZEND_ARG_INFO(0, str)
ZEND_END_ARG_INFO()
/* }}} */

/* {{{ hello_functions[]
 */
static const zend_function_entry hello_functions[] = {
	PHP_FE(hello_test1,		arginfo_hello_test1)
	PHP_FE(hello_test2,		arginfo_hello_test2)
	PHP_FE_END
};
/* }}} */

/* {{{ hello_module_entry
 */
zend_module_entry hello_module_entry = {
	STANDARD_MODULE_HEADER,
	"hello",					/* Extension name */
	hello_functions,			/* zend_function_entry */
	NULL,							/* PHP_MINIT - Module initialization */
	NULL,							/* PHP_MSHUTDOWN - Module shutdown */
	PHP_RINIT(hello),			/* PHP_RINIT - Request initialization */
	NULL,							/* PHP_RSHUTDOWN - Request shutdown */
	PHP_MINFO(hello),			/* PHP_MINFO - Module info */
	PHP_HELLO_VERSION,		/* Version */
	STANDARD_MODULE_PROPERTIES
};
/* }}} */

#ifdef COMPILE_DL_HELLO
# ifdef ZTS
ZEND_TSRMLS_CACHE_DEFINE()
# endif
ZEND_GET_MODULE(hello)
#endif

刪除之前生成的擴(kuò)展文件

Rust如何開發(fā)PHP擴(kuò)展

重新生成擴(kuò)展Rust如何開發(fā)PHP擴(kuò)展

phpize
./configure --with-php-config=/www/server/php/74/bin/php-config
make

Rust如何開發(fā)PHP擴(kuò)展

大小都變了,說明我們的靜態(tài)庫在里面了哈哈。

按上述使用擴(kuò)展流程替換擴(kuò)展

Rust如何開發(fā)PHP擴(kuò)展

注意!替換擴(kuò)展文件后要重啟PHP哦,不然不生效!

7、測試rust開發(fā)的php擴(kuò)展

Rust如何開發(fā)PHP擴(kuò)展

網(wǎng)頁測試

Rust如何開發(fā)PHP擴(kuò)展

命令行測試

Rust如何開發(fā)PHP擴(kuò)展

也可以通過php擴(kuò)展骨架直接進(jìn)行測試

Rust如何開發(fā)PHP擴(kuò)展

Rust如何開發(fā)PHP擴(kuò)展

Rust如何開發(fā)PHP擴(kuò)展

編寫要執(zhí)行測試的擴(kuò)展函數(shù)

--TEST--
hello_test2() Basic test
--SKIPIF--
<?php
if (!extension_loaded('hello')) {
	echo 'skip';
}
?>
--FILE--
<?php
hello_test1();
var_dump(hello_test2('5LiA56CB6LaF5Lq6'));
?>
--EXPECT--
string(11) "Hello World"
string(9) "Hello PHP"

Rust如何開發(fā)PHP擴(kuò)展

擴(kuò)展目錄下直接輸入:

make test

Rust如何開發(fā)PHP擴(kuò)展

執(zhí)行后 tests目錄下輸出了一個.out文件

Rust如何開發(fā)PHP擴(kuò)展

到此,相信大家對“Rust如何開發(fā)PHP擴(kuò)展”有了更深的了解,不妨來實際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI