Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PHP Fatal error: Class Foo cannot implement previously implemented interface Stringable in Unknown on line 0 #319

Closed
clearair opened this issue Aug 4, 2024 · 3 comments

Comments

@clearair
Copy link

clearair commented Aug 4, 2024

Hi
I encountered an issue with the __toString method

rust 1.80
ext-php-rs 0.12.0
php 8.3

rust code

use ext_php_rs::{info_table_end, info_table_row, info_table_start, prelude::*};
use ext_php_rs::{exception::PhpResult, types::Zval, zend::ce};
use ext_php_rs::zend::ModuleEntry;

#[php_class(name = "Foo")]
#[implements(ce::stringable())]
#[implements(ce::countable())]
#[derive(Default)]
pub struct Foo {
}

#[php_impl]
impl Foo {
    #[constructor]
    pub fn __construct() -> Self {
        Foo {
           
        }
    }

    pub fn __to_string(&self) -> String {
        format!("string")
    }

    pub fn count(&self) -> i32 {
       1
    }
}

/// Used by the `phpinfo()` function and when you run `php -i`.
pub extern "C" fn php_module_info(_module: *mut ModuleEntry) {
    info_table_start!();
    info_table_row!("Foo", "enabled");
    info_table_end!();
}

#[php_module]
pub fn module(module: ModuleBuilder) -> ModuleBuilder {
    module
}

php code

<?php

$foo = new Foo();

echo $foo;

php -d extension=./target/debug/libphp_foo.so test.php
PHP Fatal error: Class Foo cannot implement previously implemented interface Stringable in Unknown on line 0
[1] 266183 IOT instruction php -d extension=./target/debug/libphp_foo.so test.php

@EdmondDantes
Copy link
Contributor

static zend_string *zend_begin_method_decl(zend_op_array *op_array, zend_string *name, bool has_body) /* {{{ */
{
     ...some code here...


	zend_add_magic_method(ce, (zend_function *) op_array, lcname);
	if (zend_string_equals_literal(lcname, ZEND_TOSTRING_FUNC_NAME)
			&& !(ce->ce_flags & ZEND_ACC_TRAIT)) {
		add_stringable_interface(ce);
________________^^^^^^^^^^^^^^^^^
	}

	return lcname;
}
/* }}} */

If a class has a __toString() method, it automatically receives the Stringable interface, so there is no need to declare it explicitly. To fix the error, you just need to remove the line: #[implements(ce::stringable())] and the code will work.

@EdmondDantes
Copy link
Contributor

@Xenira The behavior was tested on the latest version of the library in PHP 8.3, please update accordingly.

@Xenira
Copy link
Collaborator

Xenira commented Jan 8, 2025

As the php docu contains

Stringable is implicitly present on any class that has the magic __toString() method defined, although it can and should be declared explicitly.

we should at least provide a way to add it to stubs. As interface stubs are broken anyways, we should fix this in #326 and maybe add docu

Thanks for testing

@Xenira Xenira closed this as completed Jan 8, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants