htmlburger/carbon-fields

Extended the Widget class is broken from PHP 8.1 onwards

Opened this issue · 0 comments

Version

  • Carbon Fields: 3.6.5
  • WordPress: 6.6.2
  • PHP: 8.2

Expected Behavior

I should be able to have two different classes that extend the Widget class that use the same names

Actual Behavior

I just upgraded from PHP 7.4 to 8.2 and I'm now having errors thrown when using register_widget() on two classes that both have a field named image. It gives the error:

Fatal error: Uncaught Exception: Field name "_image" already registered
in /bla/bla/bla/carbon-fields/core/Exception/Incorrect_Syntax_Exception.php on line 22

Which in the callstack is being thrown from:

Carbon_Fields\Widget\Widget::register_field_name()
bla/bla/carbon-fields/core/Widget/Widget.php:212

Comments

The issue is this bit of code here:

	public function register_field_name( $name ) {
		static $registered_field_names = array();

		if ( in_array( $name, $registered_field_names ) ) {
			Incorrect_Syntax_Exception::raise( 'Field name "' . $name . '" already registered' );
			return false;
		}

		$registered_field_names[] = $name;
		return true;
	}

specifically static $registered_field_names = array();

I believe that this functionality changed in PHP 8.1 such that $registered_field_names now contains all registered field names from that have ever gone through this method instead of being scoped to only the registered field names for the current class.

The following bit of code can be used to show the difference between PHP versions:

class Base {
    public function setThing($thing) {
        static $things = [];

        $things[] = $thing;

        var_dump($things);
    }
}

class A extends Base {
    public function setSomeThing()
    {
        $this->setThing('1');
    }
}

class B extends Base {
    public function setSomeThing()
    {
        $this->setThing('a');
    }
}

$a = new A();
$a->setSomeThing();
$b = new B();
$b->setSomeThing();

If you run this using php 7.4 you get the following output:

array(1) {
  [0]=>
  string(1) "1"
}
array(1) {
  [0]=>
  string(1) "a"
}

But with 8.2 (I'm assuming 8.1 as well but I haven't had time to test it)

array(1) {
  [0] =>
  string(1) "1"
}
array(2) {
  [0] =>
  string(1) "1"
  [1] =>
  string(1) "a"
}