Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Your first PHP extension

Your first PHP extension

Do you think the PHP interpreter is black magic and C is just like alchemy for you?

Are you interested in harnessing some of that magic for yourself?

This talk will give you an overview of how to develop an extension for PHP using rust.

You’ll see how to setup up a simple example and how to add more elaborate features to it.

After getting to know some general tips you’ll learn about some pitfalls and how to circumvent them.

Equipped with this knowledge you’ll be able to work some of that PHP interpreter magic yourself.

Christian Rades

February 16, 2023
Tweet

More Decks by Christian Rades

Other Decks in Technology

Transcript

  1. @c_rades Hi everyone! My name Is Christian Resident mad man@shopware

    @C_Rades(@phpc.social) Your fi rst php extension
  2. Your fi rst php extension @c_rades # ... languages.rust.enable =

    true; languages.nix.enable = true; languages.php = { enable = true; package = phpunwrapped.buildEnv { extensions = {enabled, all}: enabled ++ (with all; [ readline ]); extraCon fi g = "memory_limit = -1"; }; }; # ...
  3. Your fi rst php extension @c_rades use ext_php_rs::prelude::*; #[php_function] pub

    fn hello_world(name: &str) -> String { format!("Hello, {}!", name) } #[php_module] pub fn get_module(module: ModuleBuilder) -> ModuleBuilder { module }
  4. Your fi rst php extension @c_rades #[php_function] pub fn transform(styles:

    &str) -> Result<String> { let mut css = StyleSheet::parse(styles, ParserOptions::default()) .map_err(|err| anyhow!("{}", err))?; css.minify(MinifyOptions::default())?; let mut con fi g = PrinterOptions::default(); con fi g.minify = true; Ok(css.to_css(con fi g)?.code) }
  5. Your fi rst php extension @c_rades #[php_impl] impl CssTransformer {

    pub fn __construct() -> Self { // ... } pub fn transform(&self, styles: &str) -> Result<String> { // ... } }
  6. Your fi rst php extension @c_rades pub fn __construct() ->

    Self { CssTransformer { browsers: Browsers::default(), minify: true, } }
  7. Your fi rst php extension @c_rades pub fn transform(&self, styles:

    &str) -> Result<String> { // ... let minify_conf = MinifyOptions { targets: Some(self.browsers.clone()), unused_symbols: HashSet::default(), }; // ... con fi g.minify = self.minify; Ok(css.to_css(con fi g)?.code) }
  8. Your fi rst php extension @c_rades $t = new Phlash\Transformer();

    $css = $t->transform( 'body { -webkit-border-radius: 2px; border-radius: 2px; }' ); var_dump($css); $ string(24) "body{border-radius:2px;}"
  9. Your fi rst php extension @c_rades $t = new Phlash\Transformer([

    'minify' => true, 'targets' => [ 'chrome' => '95.1.0' ], ]);
  10. Your fi rst php extension @c_rades #[optional(con fi g)] pub

    fn __construct(con fi g: Option<&ZendHashTable>) -> Result<Self> { let mut base = CssTransformer {// ...}; let Some(con fi g_ht) = con fi g else { return Ok(base); }; for (_idx, key, val) in con fi g_ht.iter() { // ... } }
  11. Your fi rst php extension @c_rades for (_idx, key, val)

    in con fi g_ht.iter() { let Some(key) = key else { continue }; match key.as_ref() { "targets" => { let map = val.array().ok_or(anyhow!("targets must be an array"))?; if let Some(version) = map.get("chrome").and_then(Zval::str) { base.browsers.chrome = Some(semver_to_u32(version)?); } } "minify" => { base.minify = val.bool().unwrap_or_default(); } _ => {} } }
  12. Your fi rst php extension @c_rades $t = new Phlash\Transformer([

    'minify' => true, 'targets' => [ 'chrome' => '95.1.0' ], ]); $css = $t->transform( 'body { -webkit-border-radius: 2px; border-radius: 2px; }' ); var_dump($css); $ string(24) "body{border-radius:2px;}"
  13. Your fi rst php extension @c_rades • The repo: https://github.com/Christian-Rades/Phlash

    • The rust crate: https://davidcole1340.github.io/ext-php-rs/introduction.html • Learning rust: https://doc.rust-lang.org/book/ • Devenv: https://devenv.sh/