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

Reply via email to