[DDC-717] Do not use files when using proxy autogeneration Created: 22/Jul/10 Updated: 04/Jul/11 |
|
| Status: | Open |
| Project: | Doctrine 2 - ORM |
| Component/s: | ORM |
| Affects Version/s: | None |
| Fix Version/s: | 2.x |
| Security Level: | All |
| Type: | Improvement | Priority: | Major |
| Reporter: | Jaka Jancar | Assignee: | Benjamin Eberlei |
| Resolution: | Unresolved | Votes: | 2 |
| Labels: | None | ||
| Description |
|
Proxy classes are generated in less than 1ms for me. I prefer to not have a "build" step to reducing loading time by a milisecond, so I use autogenerate. For users like me, wouldn't it be nicer if we wouldn't even have to configure a proxy dir and those files were never written (since they're not read more than once anyway)? |
| Comments |
| Comment by Jaka Jancar [ 22/Jul/10 ] |
|
This very minimal patch removes the use of these temporary files: --- library/Doctrine/ORM/Proxy/ProxyFactory.php (revision 2)
+++ library/Doctrine/ORM/Proxy/ProxyFactory.php (working copy)
@@ -78,9 +78,8 @@
$fqn = $this->_proxyNamespace . '\\' . $proxyClassName;
if ($this->_autoGenerate && ! class_exists($fqn, false)) {
- $fileName = $this->_proxyDir . DIRECTORY_SEPARATOR . $proxyClassName . '.php';
- $this->_generateProxyClass($this->_em->getClassMetadata($className), $proxyClassName, $fileName, self::$_proxyClassTemplate);
- require $fileName;
+ $file = $this->_generateProxyClass($this->_em->getClassMetadata($className), $proxyClassName, null, self::$_proxyClassTemplate);
+ eval('?>'.$file);
}
if ( ! $this->_em->getMetadataFactory()->hasMetadataFor($fqn)) {
@@ -144,6 +143,9 @@
$file = str_replace($placeholders, $replacements, $file);
+ if ($fileName === null)
+ return $file;
+
file_put_contents($fileName, $file);
}
|
| Comment by Benjamin Eberlei [ 23/Jul/10 ] |
|
The proxy dir is used for the "doctrine orm:generate-proxies" command in the case of "autogenerate= false", so you need to define it anyways. You have to use proxies, the option is not for Proxy yes/no. If you have autogenerate=false and doctrine requires a proxy for a use case but can't find it you will get a fatal error. |
| Comment by Benjamin Eberlei [ 23/Jul/10 ] |
|
I just saw the eval() keyword, ieeks |
| Comment by Jaka Jancar [ 23/Jul/10 ] |
|
eval() is no different than writing code to a file and using require(). When using runtime-generated proxies, there are no benefits (that I know of) from writing them to a file. The disadvantages are:
This is a nicer patch, which makes _generateProxyClass() return a string, just like other _generate* methods: --- library/Doctrine/ORM/Proxy/ProxyFactory.php (revision 2)
+++ library/Doctrine/ORM/Proxy/ProxyFactory.php (working copy)
@@ -78,9 +78,8 @@
$fqn = $this->_proxyNamespace . '\\' . $proxyClassName;
if ($this->_autoGenerate && ! class_exists($fqn, false)) {
- $fileName = $this->_proxyDir . DIRECTORY_SEPARATOR . $proxyClassName . '.php';
- $this->_generateProxyClass($this->_em->getClassMetadata($className), $proxyClassName, $fileName, self::$_proxyClassTemplate);
- require $fileName;
+ $code = $this->_generateProxyClass($this->_em->getClassMetadata($className), $proxyClassName);
+ eval($code);
}
if ( ! $this->_em->getMetadataFactory()->hasMetadataFor($fqn)) {
@@ -107,19 +106,19 @@
foreach ($classes as $class) {
$proxyClassName = str_replace('\\', '', $class->name) . 'Proxy';
$proxyFileName = $proxyDir . $proxyClassName . '.php';
- $this->_generateProxyClass($class, $proxyClassName, $proxyFileName, self::$_proxyClassTemplate);
+ $code = $this->_generateProxyClass($class, $proxyClassName);
+ file_put_contents($proxyFileName, "<?php\n" . $code);
}
}
/**
* Generates a proxy class file.
*
- * @param $class
- * @param $originalClassName
+ * @param ClassMetadata $class
* @param $proxyClassName
- * @param $file The path of the file to write to.
+ * @return string The code of the generated methods.
*/
- private function _generateProxyClass($class, $proxyClassName, $fileName, $file)
+ private function _generateProxyClass(ClassMetadata $class, $proxyClassName)
{
$methods = $this->_generateMethods($class);
$sleepImpl = $this->_generateSleep($class);
@@ -142,9 +141,9 @@
$methods, $sleepImpl
);
- $file = str_replace($placeholders, $replacements, $file);
+ $file = str_replace($placeholders, $replacements, self::$_proxyClassTemplate);
- file_put_contents($fileName, $file);
+ return $file;
}
/**
@@ -244,8 +243,7 @@
/** Proxy class code template */
private static $_proxyClassTemplate =
-'<?php
-
+'
namespace <namespace>;
/**
|
| Comment by Benjamin Eberlei [ 24/Jul/10 ] |
|
Scheduled usage of eval() for 2.1, if the following conditions exist: 1. Autogenerate is set to TRUE |
| Comment by Jaka Jancar [ 24/Jul/10 ] |
|
Great, this is even better. This way you can have 1) autogenerated in ram-only, 2) autogenerated in files and 3) pregenerated. And the minimal amount of config needed to get up and running is reduced, which is always nice. |
| Comment by Benjamin Eberlei [ 24/Jul/10 ] |
|
you should know though, eval is dead slow. It generates the necessary proxies on EACH request and that cannot be cached in APC. |
| Comment by Jaka Jancar [ 24/Jul/10 ] |
|
It's no slower than current autogeneration (file_put_contents+require). TBH, I don't know why anyone would want to use that over eval(), but I don't mind it being there. Pre-generation is, of course, a different thing. Seems like a valid tradeoff to offer: build/a bit of config/better perfomance vs. no build/no config/potentially slower. |
| Comment by Benjamin Eberlei [ 24/Jul/10 ] |
|
Yes, that is because file_put_contents + require is a development only strategy. The manual clearly states that autogenerate has to be false in production. |
| Comment by Roman S. Borschel [ 12/Aug/10 ] |
|
Using eval() instead of producing and requiring the file in the case of enabled auto-generation of proxy classes sounds like a good improvement for 2.1 to make proxies more transparent during deveopment and for anyone for whom performance is no issue. I'm increasing the priority as I think it is easy to implement for 2.1 and a good enhancement. |
| Comment by Karsten Dambekalns [ 09/Feb/11 ] |
|
A note on why having the proxies written to a file can be useful even with autogenerate being on: it makes it really easy to check the proxy code being generated. I use that a lot currently. The solution suggested, giving three possibilities is cool, though. |