Re: Failing to write to a file when a class is being implicitly destroyed

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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


[Index of Archives]     [PHP Home]     [Apache Users]     [PHP on Windows]     [Kernel Newbies]     [PHP Install]     [PHP Classes]     [Pear]     [Postgresql]     [Postgresql PHP]     [PHP on Windows]     [PHP Database Programming]     [PHP SOAP]

  Powered by Linux