phptools-docs icon indicating copy to clipboard operation
phptools-docs copied to clipboard

Undefined property on class with `#[\AllowDynamicProperties]` attribute

Open vitkutny opened this issue 1 year ago • 3 comments

Code:

namespace Test {

	#[\AllowDynamicProperties]
	final class DynamicTemplate
	{
	}

	$template = new DynamicTemplate();
	echo $template->bar; # Undefined property: DynamicTemplate::$bar PHP0416


	final class MagicTemplate
	{
		public function __get(string $name): mixed
		{
			return null;
		}
	}

	$template = new MagicTemplate();
	echo $template->bar; # OK – no error

}

There shoulde be no error when class is marked with #[\AllowDynamicProperties] for back compatibility with php 8.2 deprecated dynamic properties unless this attribute is present

vitkutny avatar Aug 17 '24 07:08 vitkutny

We do check unknown properties for any class; the attribute AllowDynamicProperties does not have the same meaning as the use of __get function.

In this sample above, the error PHP0416 is correct since the class does not have that property and the code will fail in run-time.

jakubmisek avatar Aug 17 '24 12:08 jakubmisek

In this sample above, the error PHP0416 is correct since the class does not have that property and the code will fail in run-time.

It will fail, because i oversimplified the code – the property was not set before. Here is the code when both cases are working same – but one is reporting problem – but no error is thrown runtime – dynamic properties are allowed in PHP – deprecated with ability to still them with AllowDynamicProperties attribute


namespace Test {

	#[\AllowDynamicProperties]
	final class DynamicTemplate
	{
	}

	$template = new DynamicTemplate();
	$template->bar = 'foo';
	echo $template->bar; # Undefined property: DynamicTemplate::$bar PHP0416


	final class MagicTemplate
	{
		public function __get(string $name): mixed
		{
			return $this->{$name};
		}
	}

	$template = new MagicTemplate();
	$template->bar = 'foo';
	echo $template->bar; # OK – no error

}

I think classes with __get/__set/__issets could be treated same as with #[\AllowDynamicProperties] attribute.

Basically the attributed class:

	#[\AllowDynamicProperties]
	final class DynamicTemplate
	{
	}

behaves same as class with magic methods:

	final class DynamicTemplate
	{
		public function __get(string $name): mixed
		{
			return $this->{$name};
		}

		public function __set(string $name, mixed $value): mixed
		{
			return $this->{$name} = $value;
		}

		public function __isset(string $name): mixed
		{
			return \property_exists($this, $name);
		}
	}

It is implemeneted like this (using attribute) in Nette framework template objects: https://github.com/nette/application/blob/master/src/Bridges/ApplicationLatte/DefaultTemplate.php

Just by adding simple __get implementation into DefaultTemplate all reported problems are resolved – but there is no need for it to be there – as it is the default php behaviour.

	public function __get(string $name): mixed {
		return $this->{$name};
	}

vitkutny avatar Aug 18 '24 10:08 vitkutny

AllowDynamicProperties is something different.

~~The warning about an unknown property has nothing to do with the class dynamicity; we simply warn about a property whose use will cause a runtime error.~~

The diagnostic PHP0416 marks property access which may cause a run-time error - i.e. is not defined dynamically or statically.

jakubmisek avatar Aug 18 '24 21:08 jakubmisek