@@ -887,6 +887,9 @@ private function createService(Definition $definition, $id, $tryProxy = true)
887
887
$ arguments = $ this ->resolveServices ($ parameterBag ->unescapeValue ($ parameterBag ->resolveValue ($ definition ->getArguments ())));
888
888
889
889
if (null !== $ factory = $ definition ->getFactory ()) {
890
+ if ($ definition ->getOverriddenGetters ()) {
891
+ throw new RuntimeException (sprintf ('Cannot dump definition: The "%s" service has both a factory and overridden getters but these are incompatible. ' , $ id ));
892
+ }
890
893
if (is_array ($ factory )) {
891
894
$ factory = array ($ this ->resolveServices ($ parameterBag ->resolveValue ($ factory [0 ])), $ factory [1 ]);
892
895
} elseif (!is_string ($ factory )) {
@@ -905,11 +908,16 @@ private function createService(Definition $definition, $id, $tryProxy = true)
905
908
} else {
906
909
$ r = new \ReflectionClass ($ parameterBag ->resolveValue ($ definition ->getClass ()));
907
910
908
- $ service = null === $ r ->getConstructor () ? $ r ->newInstance () : $ r ->newInstanceArgs ($ arguments );
909
-
910
911
if (!$ definition ->isDeprecated () && 0 < strpos ($ r ->getDocComment (), "\n * @deprecated " )) {
911
912
@trigger_error (sprintf ('The "%s" service relies on the deprecated "%s" class. It should either be deprecated or its implementation upgraded. ' , $ id , $ r ->name ), E_USER_DEPRECATED );
912
913
}
914
+ if ($ definition ->getOverriddenGetters ()) {
915
+ $ salt = str_replace ('. ' , '' , uniqid ('' , true ));
916
+ $ service = eval (sprintf ('return new class(...$arguments) extends %s { private $container%3$s; private $values%3$s; %s }; ' , $ r ->name , $ this ->addOverriddenGetters ($ id , $ definition , $ r , $ salt ), $ salt ));
917
+ call_user_func (\Closure::bind (function ($ c , $ v , $ s ) { $ this ->{'container ' .$ s } = $ c ; $ this ->{'values ' .$ s } = $ v ; }, $ service , $ service ), $ this , $ definition ->getOverriddenGetters (), $ salt );
918
+ } else {
919
+ $ service = null === $ r ->getConstructor () ? $ r ->newInstance () : $ r ->newInstanceArgs ($ arguments );
920
+ }
913
921
}
914
922
915
923
if ($ tryProxy || !$ definition ->isLazy ()) {
@@ -1114,6 +1122,58 @@ public function getEnvCounters()
1114
1122
return $ this ->envCounters ;
1115
1123
}
1116
1124
1125
+ private function addOverriddenGetters ($ id , Definition $ definition , \ReflectionClass $ class , $ salt )
1126
+ {
1127
+ if (PHP_VERSION_ID < 70000 ) {
1128
+ throw new RuntimeException (sprintf ('Getter-based injection requires PHP 7 or more as used for service "%s". ' , $ id ));
1129
+ }
1130
+ if ($ class ->isFinal ()) {
1131
+ throw new RuntimeException (sprintf ('Invalid getter for service "%s": class "%s" is final. ' , $ id , $ class ->name ));
1132
+ }
1133
+ $ getters = '' ;
1134
+ foreach ($ definition ->getOverriddenGetters () as $ name => $ returnValue ) {
1135
+ if (!$ class ->hasMethod ($ name )) {
1136
+ throw new RuntimeException (sprintf ('Invalid getter for service "%s": method "%s::%s" does not exist. ' , $ id , $ class ->name , $ name ));
1137
+ }
1138
+ $ r = $ class ->getMethod ($ name );
1139
+ if ($ r ->isPrivate ()) {
1140
+ throw new RuntimeException (sprintf ('Invalid getter for service "%s": method "%s::%s" is private. ' , $ id , $ class ->name , $ name ));
1141
+ }
1142
+ if ($ r ->isFinal ()) {
1143
+ throw new RuntimeException (sprintf ('Invalid getter for service "%s": method "%s::%s" is final. ' , $ id , $ class ->name , $ name ));
1144
+ }
1145
+ if ($ r ->returnsReference ()) {
1146
+ throw new RuntimeException (sprintf ('Invalid getter for service "%s": method "%s::%s" returns by reference. ' , $ id , $ class ->name , $ name ));
1147
+ }
1148
+ if (0 < $ r ->getNumberOfParameters ()) {
1149
+ throw new RuntimeException (sprintf ('Invalid getter for service "%s": method "%s::%s" has parameters. ' , $ id , $ class ->name , $ name ));
1150
+ }
1151
+ if ($ type = $ r ->getReturnType ()) {
1152
+ $ type = ': ' .($ type ->allowsNull () ? '? ' : '' ).$ this ->generateTypeHint ($ type , $ r );
1153
+ }
1154
+ $ visibility = $ r ->isProtected () ? 'protected ' : 'public ' ;
1155
+ $ nameExport = var_export ($ name , true );
1156
+ $ getters .= <<<EOF
1157
+
1158
+ {$ visibility } function {$ name }() {$ type } {
1159
+ \$c = \$this->container $ salt;
1160
+ \$b = \$c->getParameterBag();
1161
+ \$v = \$this->values {$ salt }[ {$ nameExport }];
1162
+
1163
+ foreach ( \$c->getServiceConditionals( \$v) as \$s) {
1164
+ if (! \$c->has( \$s)) {
1165
+ return parent:: {$ name }();
1166
+ }
1167
+ }
1168
+
1169
+ return \$c->resolveServices( \$b->unescapeValue( \$b->resolveValue( \$v)));
1170
+ }
1171
+ EOF ;
1172
+ }
1173
+
1174
+ return $ getters ;
1175
+ }
1176
+
1117
1177
/**
1118
1178
* Returns the Service Conditionals.
1119
1179
*
0 commit comments