basically when php shutsdown at some stage stuff like file manipulation, db access will have been torn down - the implicit object destruction (and therefore the call to __destruct() happens to late in the shutdown process to be of any use ... there is a big chicken and egg problem there (search the archives of the php-internal mailing list should reveal lots of discussion surround this topic) further comments below ... John Wells wrote:
I hope I can explain my problem/questions clearly. Thanks in advance: ------------ Scenario: I'm working on a Log class that my app will use to write debug/error/etc messages to a file. I've created it so that as the application logs messages, these messages are queued within a property of the Log class, and only written to the file when the Log object is being destroyed. I wanted to place all of the file writing to within __destruct() to avoid holding a connection to the log file throughout the life of the app's state. ------------ Problem: Everything works fine, UNLESS I move the fopen('log-file-name') call to within the __destruct() method. If I open a handle to the log file within the __construct() method, or any other class method, it works fine. But I receive a permissions error if it's called within __destruct(). Error reads: "Warning: fopen(20060331.txt) [function.fopen]: failed to open stream: Permission denied in ......." ------------ Caveat: I have found that if I explicitly destroy an instance of Log with unset(), then fopen() will work even when it is within the __destruct() method. However I don't like that solution...and besides, I'm planning on creating an instance of the Log class from within the __construct() of my Controller class, and trying to explicitly destroy Log with an implicit __destruct() of my Controller doesn't work either. :P
that's probably due to references still existing (according to the engine) to you Log object.
------------ Question(s): 1. Could anyone explain a bit more as to why fopen() won't work within an implicit call to __destruct()? What permissions has my app lost at this point?
it's seems rather odd that the error would return a permission problem. I don't get that at all.
2. Am I at least correct in my intention to limit the duration that the handle to the log file is open?
it's a good idea yes - any system will have some kind of max as to the number of open files that are allowed/capable.
3. Is there workaround to this little conundrum that anyone can think of?
explicit destruction. may try working with register_shutdown_function() - the ctor of your log object could register a 'flsuh' method to be run at shutdown (which may well be at an early enough stage that opening/writing files is still possible) personally I avoid __destruct() - it gives me headaches and never seems capable of doing what I think it should be able to!
------------ Code: Here's a simplified version of the code (it's complete, feel free to copy-and-paste-and-play). I've commented the fopen code block in question. [code] // Create an instance of Log $log = new Log(); // Attempt to log a message Log::debug("Here is a debug message."); class Log { protected static $handle; protected static $location; protected static $message; public function __construct() { self::$location = date("Ymd").".txt"; /* Begin fopen() */ /* When placed here, it works */ if (!self::$handle = fopen(self::$location,"a")) { echo "Error. Please check permissions."; die; } /* End fopen() */ } public static function debug($message) { $timestamp = date("Y-m-d H:i:s T"); self::$message .= $timestamp."\tdebug\t".$message."\n"; } public function __destruct() { if(self::$message) { /* Begin fopen() */ /* If it's here, it won't work! if (!self::$handle = fopen(self::$location,"a")) { echo "There was an error attempting to open the log file. Please check permissions."; die; } /* End fopen() */ if (fwrite(self::$handle, self::$message) === FALSE) { echo "Cannot write to file ({$this->location})"; exit;
the 'die' and 'exit' in the code directly above is probably a really bad idea! and given that the code is currently living in a dtor rather unnecessary?
} @fclose(self::$handle); } } } [/code] -John W
-- PHP General Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php