Skip to content

[WIP][DependencyInjection] Add a new Syntax to define factories as callables. #9839

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

Closed
wants to merge 2 commits into from

Conversation

realityking
Copy link
Contributor

Q A
Bug fix? yes
New feature? yes
BC breaks? no
Deprecations? yes
Tests pass? yes
Fixed tickets -
License MIT
Doc PR -

This pull requests adds a new syntax to define factories based on the syntax for configurators. This is more flexible than the old syntax (factoryMethod and either of factoryClass or factoryService), as it also allows for functions as factories.

Since the service is now a Reference to a Definition it also allows us to inline factories for a small performance improvement and better encapsulation.

Lastly this prevents a bug where a private factory is simple removed because it's not referenced in the graph.

I did not change any of the existing definitions (there's one use of a factory in FrameworkBundle) or automatically use the new internal representation when parsing YAML or XML definitions because this could introduce subtle B/C issues.

There are still a few things left to do (see list below), I wanted a general thumbs up on the approach and the deprecation before I continue.

Todo:

  • Write documentation
  • Update UPGRADE-3.0.md
  • Add a check to CheckDefinitionValidityPass to validate only one factory is defined.

@sstok
Copy link
Contributor

sstok commented Dec 22, 2013

just a random thought This will make setting factories easier, and so would also allow Expressions as factory, as it does not make sense to use service of class for this.
And it just might solve the issue were one needs dynamic services (like #9658), but expressions are none static and a service 'should' not change except for prototype and request scope.

But this is just random thought, so nothing concrete.

@stof
Copy link
Member

stof commented Dec 23, 2013

the new API seems easier to use. However, the Definition now has 2 different factories stored in it, which can lead to weird state when manipulating it. the deprecated API should be reimplemented on top of the new API IMO, to make it only a BC layer

@realityking
Copy link
Contributor Author

I'm relatively sure this will lead to really weird edge cases. For example, if I set the factory to an object (not a service nor a class), than I will get a result for factoryMethod but neither factoryClass nor factoryService. Not sure everything outside out control can handle that.

@stof
Copy link
Member

stof commented Dec 27, 2013

@realityking This case should be forbidden, because it will not be possible to dump the container if you pass an object

@realityking
Copy link
Contributor Author

@stof The dumpers already check for that and throw an exception if they encounter an object. Shouldn't this remain consistent?

@@ -56,6 +57,34 @@ public function __construct($class = null, array $arguments = array())
}

/**
* Sets a factory
*
* @param callable $callable A PHP callable
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it make sense to support strings like 'class_name::method' or a service call like 'service_name.method_name' (both of which being supported elsewhere in the framework)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Starting with PHP 5.2.3 (no typo), class_name::method should work just fine as they're valid PHP callable.

As for the service_name.method_name syntax, I'd have to take a look how complex that'd be to do. Where else is this used?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@realityking Actually, I made a typo, i meant service_name:method_name. Support should be relatively easy as this would be converted to something like $container->get('service_name')->method_name()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't that create a fair amount ambiquity? What if I have a service and and a class with the same name?

I'll have to change this comment though, since it's not really a PHP callable I expect. It also accepts a Reference or Definition and a method name as an array.

That said, if we allow a plain service name instead of a reference we'll break the inlining and get the weird bug with private services again. The only solution to that would be to do the conversion at parse time - but than I don't know all the services and get back to the problem above.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where do see an ambiguity? It's :, not :: for service calls.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah sorry, didn't look careful enough.

With that information, would it be ok to do this at the parser level and only allow this syntax in YAML and XML but not when directly manipulating the Definition?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, support is only relevant for the YAML and XML formats.

@realityking
Copy link
Contributor Author

@fabpot I added the service:method short syntax, but only for YAML. I did not add it for XML because after looking at the code, it just isn't a good fit. Currently the service, method and class are different attributes on the factory element. I wouldn't want to change that either, because that make the syntax different from configurators.

If you think this is still worthwhile with just YAML support, than I'll add the same for configurators in a different pull request to keep them in sync.

@realityking
Copy link
Contributor Author

@fabpot Any feedback on using the short hand syntax only for YAML? I'd like to write the documentation to get this done.

@realityking
Copy link
Contributor Author

@fabpot Ping. I'd like to write the docs to get this done.

@realityking
Copy link
Contributor Author

@fabpot I know the ship has sailed for 2.5, but could you give me some feedback about the short hand syntax? (only for YAML or not at all)

@@ -18,6 +18,11 @@ UPGRADE FROM 2.x to 3.0
`DebugClassLoader`. The difference is that the constructor now takes a
loader to wrap.

### DependencyInjection

* The methods `setFactoryClass()`, `setFactoryMethod()` and `setFactoryService()`have been removed in favor of `setFactory`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there should be a space before "have been removed"

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and setFactory() (to be consistent?)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, fixed.

@@ -65,6 +94,7 @@ public function __construct($class = null, array $arguments = array())
* @return Definition The current instance
*
* @api
* @deprecated Deprecated since version 2.5, to be removed in 3.0.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since version 2.6

@fabpot
Copy link
Member

fabpot commented Sep 24, 2014

Don't know why this one slipped under the radar. I'm going to submit a new PR to fix some small things (mainly CS and updated to current master) -- see #12008.

Thanks @realityking for this great work and sorry again for the delay. Can you submit a PR for the documentation?

@fabpot fabpot closed this Sep 24, 2014
fabpot added a commit that referenced this pull request Sep 24, 2014
…ries as callables (realityking, fabpot)

This PR was merged into the 2.6-dev branch.

Discussion
----------

[DependencyInjection] Add a new Syntax to define factories as callables

| Q             | A
| ------------- | ---
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | yes
| Tests pass?   | yes
| Fixed tickets | -
| License       | MIT
| Doc PR        | -

From the original PR #9839:

"This pull requests adds a new syntax to define factories based on the syntax for configurators. This is more flexible than the old syntax (factoryMethod and either of factoryClass or factoryService), as it also allows for functions as factories.

Since the service is now a Reference to a Definition it also allows us to inline factories for a small performance improvement and better encapsulation.

Lastly this prevents a bug where a private factory is simple removed because it's not referenced in the graph.

I did not change any of the existing definitions (there's one use of a factory in FrameworkBundle) or automatically use the new internal representation when parsing YAML or XML definitions because this could introduce subtle B/C issues.
"

Commits
-------

187aeee fixed CS
bd8531d added a new Syntax to define factories as callables.
@realityking
Copy link
Contributor Author

Awesome, I already wrote this off. I'll see that I get to the docs on the weekend.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants