Closed EtienneBruines closed 3 years ago
Any idea on how to fix it?
The only "working" solution so far has been to make Validator
not (statically) dependent on DateValidator
. The two constants (TYPE_DATETIME
and TYPE_TIME
) would then be defined on the Validator
class and not the DateValidator
class.
For backwards-compatibility, one would probably define those constants on Validator
as well as on DateValidator
, but with the same values.
class Validator extends Component
{
public const TYPE_DATETIME = 'datetime';
public const TYPE_TIME = 'time';
}
class DateValidator extends Validator
{
public const TYPE_DATETIME = Validator::TYPE_DATETIME;
public const TYPE_TIME = Validator::TYPE_TIME;
}
Alternatively, depending on personal preference:
Separate classes for DateTimeValidator
and TimeValidator
(possibly extending DateValidator
), so the class member type
does not need to be configured for the Validator::$builtInValidators
static variable.
Does it work if you include also UrlValidator,
UniqueValidatorand
StringValidator`?
@rob006 Unfortunately not. It is really related to the DateValidator::TYPE_DATETIME
and DateValidator::TYPE_TIME
statements.
Author right, because all classes are loaded according to their hierarchy. When compiling yii\base\Validator
, the preloader does not know anything about yii\base\DateValidator
yet. If yii\base\DateValidator
is loaded before yii\base\Validator
, everything happens exactly the opposite.
There are actually two ways out.
yii\base\DateValidatorInterface
and to transfer in it constants, use it in yii\base\Validator
and implements in yii\base\DateValidator
.// crutch interface
interface DateValidatorInterface
{
const TYPE_DATE = 'date';
const TYPE_DATETIME = 'datetime';
const TYPE_TIME = 'time';
}
use DateValidatorInterface;
class Validator extends Component
{
public static $builtInValidators = [
...
'datetime' => [
'class' => 'yii\validators\DateValidator',
'type' => DateValidatorInterface::TYPE_DATETIME,
],
'time' => [
'class' => 'yii\validators\DateValidator',
'type' => DateValidatorInterface::TYPE_TIME,
],
...
];
}
class DateValidator extends Validator implements DateValidatorInterface
{
}
and preload DateValidatorInterface
before yii\validators\Validator
yii\base\Validator
a la date
, datetime
and force them to register in yii\base\Model::rules()
.class Validator extends Component
{
public static $builtInValidators = [
...
'datetime' => [
'class' => 'yii\validators\DateValidator',
]
...
];
}
I'm afraid the third option hasn't occurred to me yet. Please don't throw tomatoes for such delusional ideas)
You could use require
instead of opcache_compile_file()
- it should trigger autoloading and load all necessary classes in correct order.
@rob006 Yeah, there's a fairy tale that require might help us. Except for one problem. Require throws a fatal error in case of a file search problem. Neither include nor require is working at the moment. Fatal errors are thrown out because DateTimeValidator is not defined in the so-called compilation. In any case, I will be glad to see a real working piece of code that can solve the warning problem.
@brussens Do you have enabled Composer autoloader while loading these files? Also PHP 7.4.1 should have some fixes related to autoloading, it may be worth checking this on this version.
@rob006 It's quite possible that at 7.4.1 this was fixed. Now I'm finishing the compilation of 7.4.1 RC, so let's see what comes out of it.
In general, 7.4.1RC1 is better, but still does not work. On Linux, unfortunately, there is no way to try it yet, since 7.3 is everywhere. Windows 10x64:
PHP Fatal error: Class yii\web\UrlNormalizerRedirectException uses internal class Throwable during preloading, which is not supported on Windows in Unknown on line 0
Apparently, classes that implement system interfaces cannot be connected via include.
Classes with dependencies on internal classes cannot be preloaded on Windows at all - this is known limitation of preloading.
Tonight I'll try to finish the preloader and put it out.
By the way, experimentally it turned out that the php daemon simply falls on Windows when trying to preload some classes. This behavior is not quite clear, but such files are essentially 2:
yii\log\FileTarget
yii\db\mysql\Schema
yii\db\mysql\QueryBuilder
can't be preloaded because yii\db\mysql\Schema
not exists in preload.
But we need a cross-platform solution to this problem, so I will install Debian today and make an extension for preload.
@brussens any luck with it?
@samdark currently experimenting with writing a plugin for composer
@samdark @brussens Any solutions so far?
No.
I don't think we should attempt to solve this in Yii2 at all. We should however take this issue to heart as one of the reasons we should try to avoid static properties / dependencies, and make 100% sure we don't have them in Yii3.
This article does have some insights into how the errors of OP can be avoided: https://stitcher.io/blog/preloading-in-php-74
@SamMousa I don't think it is related to static properties / dependencies. It is more like a problem of recursive dependencies in class definitions - you need to have Validator
definition in order to parse DateValidator
, but you need DateValidator
definition in order to parse Validator
. You probably will get the same problem with constant or non-static property.
BTW: Is anyone tested this issue with autoloader & class_exists()
instead of opcache_compile_file()
(on non-windows environment)? Preloading had rough start, but I would be surprised if this would still not work.
The first error in OP is about static properties, it causes in this example, Validator
to not get preloaded. This in turn causes subclasses to fail.
The dependency loading can be automated using the autoloader, that's explained in the article I mentioned.
The first error in OP is about static properties
It is not because of static property, it is because parent class uses symbols from child class in its definition, so you have chicken-egg problem. You will get exact the same result with non-static property or constant.
Also I have verified this issue with autoloader + class_exists()
and preloading works fine, so I suggest to just close this issue - using opcache_compile_file()
in preloading scripts seems to be pretty niche anyway.
It is not because of static property, it is because parent class uses symbols from child class in its definition, so you have chicken-egg problem. You will get exact the same result with non-static property or constant.
Ah, I see now what the static property default value is.. you're right. And I agree with closing it :)
What steps will reproduce the problem?
Using PHP 7.4 with preloading.
What is the expected result?
No errors.
What do you get instead?
Preload.php
Problem guesstimate
Circular reference between
Validator
(in$builtInValidators
) andDateValidator
.Additional info