Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ jobs:
- name: Setup Mago
uses: nhedger/setup-mago@v2
with:
version: 1.49.0
version: 1.57.0
- name: Check PHP formatting
run: mago format --check
- name: Lint PHP
Expand Down
2 changes: 1 addition & 1 deletion benches/benches/array_interned_keys.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?php

declare(strict_types = 1);
declare(strict_types=1);

$a = bench_array_with_interned_keys((int) $argv[1]);
2 changes: 1 addition & 1 deletion benches/benches/array_str_ref_keys.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?php

declare(strict_types = 1);
declare(strict_types=1);

$a = bench_array_with_str_ref_keys((int) $argv[1]);
2 changes: 1 addition & 1 deletion benches/benches/binary_slice.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php

declare(strict_types = 1);
declare(strict_types=1);

$packed = pack('P*', ...range(1, 64));

Expand Down
2 changes: 1 addition & 1 deletion benches/benches/callback_call.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?php

declare(strict_types = 1);
declare(strict_types=1);

bench_callback_function(fn($i) => $i * 2, (int) $argv[1]);
2 changes: 1 addition & 1 deletion benches/benches/exception_throw.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php

declare(strict_types = 1);
declare(strict_types=1);

$n = (int) $argv[1];

Expand Down
2 changes: 1 addition & 1 deletion benches/benches/function_call.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php

declare(strict_types = 1);
declare(strict_types=1);

$n = (int) $argv[1];

Expand Down
2 changes: 1 addition & 1 deletion benches/benches/method_call.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php

declare(strict_types = 1);
declare(strict_types=1);

$obj = new BenchClass();

Expand Down
2 changes: 1 addition & 1 deletion benches/benches/object_new.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php

declare(strict_types = 1);
declare(strict_types=1);

$n = (int) $argv[1];

Expand Down
2 changes: 1 addition & 1 deletion benches/benches/output_passthrough.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php

declare(strict_types = 1);
declare(strict_types=1);

$chunk = str_repeat('a', 1024);

Expand Down
2 changes: 1 addition & 1 deletion benches/benches/output_transform.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php

declare(strict_types = 1);
declare(strict_types=1);

$chunk = str_repeat('a', 1024);

Expand Down
2 changes: 1 addition & 1 deletion benches/benches/property_compare.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php

declare(strict_types = 1);
declare(strict_types=1);

$a = new BenchProps(42, 'hello');
$b = new BenchProps(42, 'hello');
Expand Down
2 changes: 1 addition & 1 deletion benches/benches/property_compound.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php

declare(strict_types = 1);
declare(strict_types=1);

$obj = new BenchProps(0, '');

Expand Down
2 changes: 1 addition & 1 deletion benches/benches/property_dump.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php

declare(strict_types = 1);
declare(strict_types=1);

$obj = new BenchProps(42, 'hello');

Expand Down
2 changes: 1 addition & 1 deletion benches/benches/property_read.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php

declare(strict_types = 1);
declare(strict_types=1);

$obj = new BenchProps(42, 'hello');

Expand Down
2 changes: 1 addition & 1 deletion benches/benches/property_write.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php

declare(strict_types = 1);
declare(strict_types=1);

$obj = new BenchProps(0, '');

Expand Down
2 changes: 1 addition & 1 deletion benches/benches/static_method_call.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php

declare(strict_types = 1);
declare(strict_types=1);

$n = (int) $argv[1];

Expand Down
2 changes: 1 addition & 1 deletion benches/benches/string_call.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php

declare(strict_types = 1);
declare(strict_types=1);

$n = (int) $argv[1];

Expand Down
78 changes: 45 additions & 33 deletions crates/macros/src/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -369,18 +369,11 @@ impl<'a> Function<'a> {
let ident = self.ident;
let arg_names: Vec<_> = self.args.typed.iter().map(|arg| arg.name).collect();

let variadic_bindings = self.args.typed.iter().filter_map(|arg| {
if arg.variadic {
let name = arg.name;
let variadic_name = format_ident!("__variadic_{}", name);
let clean_ty = arg.clean_ty();
Some(quote! {
let #variadic_name = #name.variadic_vals::<#clean_ty>();
})
} else {
None
}
});
let variadic_bindings = self
.args
.typed
.iter()
.filter_map(TypedArg::variadic_binding);

let arg_accessors = self.args.typed.iter().map(|arg| {
arg.accessor(|e| {
Expand Down Expand Up @@ -508,10 +501,9 @@ impl<'a> Function<'a> {
)
};

let invalid = invalid_argument(name);
let throw_invalid = quote! {
::ext_php_rs::exception::PhpException::from_message(
concat!("Invalid value given for argument `", stringify!(#name), "`.").into()
).throw();
#invalid.throw();
return;
};

Expand Down Expand Up @@ -710,18 +702,11 @@ impl<'a> Function<'a> {
.iter()
.map(TypedArg::arg_declaration)
.collect::<Vec<_>>();
let variadic_bindings = self.args.typed.iter().filter_map(|arg| {
if arg.variadic {
let name = arg.name;
let variadic_name = format_ident!("__variadic_{}", name);
let clean_ty = arg.clean_ty();
Some(quote! {
let #variadic_name = #name.variadic_vals::<#clean_ty>();
})
} else {
None
}
});
let variadic_bindings = self
.args
.typed
.iter()
.filter_map(TypedArg::variadic_binding);
let arg_accessors = self.args.typed.iter().map(|arg| {
arg.accessor(
|e| quote! { return ::ext_php_rs::class::ConstructorResult::Exception(#e); },
Expand Down Expand Up @@ -912,6 +897,20 @@ fn is_slice_ref(ty: &Type) -> bool {
matches!(ty, Type::Reference(reference) if matches!(*reference.elem, Type::Slice(_)))
}

pub(crate) fn invalid_argument(name: &Ident) -> TokenStream {
let message = format!(
"Invalid value given for argument `{}`.",
ident_to_php_name(name)
);
quote! {
::ext_php_rs::exception::PhpException::new(
#message.into(),
0,
::ext_php_rs::zend::ce::type_error(),
)
}
}

impl TypedArg<'_> {
/// Returns a 'clean type' with the lifetimes removed. This allows the type
/// to be used outside of the original function context.
Expand Down Expand Up @@ -965,6 +964,18 @@ impl TypedArg<'_> {
}
}

fn variadic_binding(&self) -> Option<TokenStream> {
if !self.variadic {
return None;
}
let name = self.name;
let variadic_name = format_ident!("__variadic_{}", name);
let ty = self.clean_ty();
Some(quote! {
let #variadic_name = #name.try_variadic_vals::<#ty>();
})
}

/// The value of the argument when the caller omitted it: the default when
/// one is declared, otherwise what the type says (`Some(None)` for
/// `Option<T>`, `None` for a required type).
Expand All @@ -979,19 +990,20 @@ impl TypedArg<'_> {
/// Get the accessor used to access the value of the argument.
fn accessor(&self, bail_fn: impl Fn(TokenStream) -> TokenStream) -> TokenStream {
let name = self.name;
let bail_invalid = bail_fn(invalid_argument(name));
if self.variadic {
let variadic_name = format_ident!("__variadic_{}", name);
return quote! {
#variadic_name.as_slice()
match #variadic_name.as_deref() {
Some(values) => values,
None => {
#bail_invalid
}
}
};
}

let ty = self.clean_ty();
let bail_invalid = bail_fn(quote! {
::ext_php_rs::exception::PhpException::from_message(
concat!("Invalid value given for argument `", stringify!(#name), "`.").into()
)
});
let reject_null = self.default.as_ref().map(|_| {
let bail_null = bail_fn(quote! {
::ext_php_rs::exception::PhpException::new(
Expand Down
7 changes: 3 additions & 4 deletions crates/macros/src/impl_interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use proc_macro2::TokenStream;
use quote::{format_ident, quote};
use syn::{FnArg, ImplItem, ItemImpl, Pat, ReturnType};

use crate::function::invalid_argument;
use crate::interface::method_name_const;
use crate::parsing::{RenameRule, ident_to_php_name, reject_php_attrs};
use crate::prelude::*;
Expand Down Expand Up @@ -200,17 +201,15 @@ fn generate_method_builder(
let arg_value_accessors: Vec<_> = args
.iter()
.map(|(name, ty)| {
let php_name = ident_to_php_name(name);
let invalid = invalid_argument(name);
quote! {
let #name: #ty = match match #name.zval() {
Some(zval) => <#ty as ::ext_php_rs::convert::FromZvalMut>::from_zval_mut(zval.dereference_mut()),
None => <#ty as ::ext_php_rs::convert::FromZvalMut>::from_missing(),
} {
Some(value) => value,
None => {
let msg = format!("Invalid value for argument `{}`", #php_name);
::ext_php_rs::exception::PhpException::from_message(msg.into())
.throw();
#invalid.throw();
return;
}
};
Expand Down
14 changes: 9 additions & 5 deletions crates/macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1425,7 +1425,8 @@ fn php_interface_internal(args: TokenStream2, input: TokenStream2) -> TokenStrea
/// should not be used on class methods - see the `#[php_impl]` macro for that.
///
/// See the [list of types](../types/index.md) that are valid as parameter and
/// return types.
/// return types. If the caller passes a value that the parameter type does not
/// accept, the call throws a `TypeError`.
///
/// A function accepts the `name`, `change_case`, `defaults` and `optional`
/// options. PHP functions have no visibility, so `#[php(vis = "...")]` is a
Expand Down Expand Up @@ -1562,9 +1563,10 @@ fn php_interface_internal(args: TokenStream2, input: TokenStream2) -> TokenStrea
///
/// A slice parameter `&[T]` in last position is variadic, the equivalent of the
/// PHP `...$args` syntax. `T` is any argument type: `&[&Zval]` receives the raw
/// values, `&[i64]` receives converted integers. A variadic parameter that is
/// not the last parameter is a compile error. The slice must be spelled in the
/// signature; a type alias that hides the slice is not detected.
/// values, `&[i64]` receives converted integers. If one of the values cannot be
/// converted into `T`, the call throws a `TypeError`. A variadic parameter that
/// is not the last parameter is a compile error. The slice must be spelled in
/// the signature; a type alias that hides the slice is not detected.
///
/// ```rust,no_run,ignore
/// # #![cfg_attr(windows, feature(abi_vectorcall))]
Expand Down Expand Up @@ -2457,7 +2459,9 @@ fn php_extern_internal(args: TokenStream2, input: TokenStream2) -> TokenStream2
/// The ordering of the variants in the enum is important, as the `FromZval`
/// implementation will attempt to parse the zval data in order. For example, if
/// you put a `String` variant before an integer variant, the integer would be
/// converted to a string and passed as the string variant.
/// converted to a string and passed as the string variant. Because an `f64` or
/// `f32` variant also accepts an integer, the integer variants must come before
/// it.
///
/// ### Examples
///
Expand Down
Loading
Loading