diff --git a/src/filesystem/TempFile.php b/src/filesystem/TempFile.php
index 536c066..41497b8 100644
--- a/src/filesystem/TempFile.php
+++ b/src/filesystem/TempFile.php
@@ -1,97 +1,111 @@
 <?php
 
 /**
  * Simple wrapper to create a temporary file and guarantee it will be deleted on
  * object destruction. Used like a string to path:
  *
  *    $temp = new TempFile();
  *    Filesystem::writeFile($temp, 'Hello World');
  *    echo "Wrote data to path: ".$temp;
  *
  * Throws Filesystem exceptions for errors.
  *
  * @task  create    Creating a Temporary File
  * @task  config    Configuration
  * @task  internal  Internals
  */
 final class TempFile {
 
   private $dir;
   private $file;
   private $preserve;
+  private $destroyed = false;
 
 /* -(  Creating a Temporary File  )------------------------------------------ */
 
 
   /**
    * Create a new temporary file.
    *
    * @param string? Filename hint. This is useful if you intend to edit the
    *                file with an interactive editor, so the user's editor shows
    *                "commit-message" instead of "p3810hf-1z9b89bas".
    * @task create
    */
   public function __construct($filename = null) {
     $this->dir = Filesystem::createTemporaryDirectory();
     if ($filename === null) {
       $this->file = tempnam($this->dir, getmypid().'-');
     } else {
       $this->file = $this->dir.'/'.$filename;
     }
 
+    // If we fatal (e.g., call a method on NULL), destructors are not called.
+    // Make sure our destructor is invoked.
+    register_shutdown_function(array($this, '__destruct'));
+
     Filesystem::writeFile($this, '');
   }
 
 
 /* -(  Configuration  )------------------------------------------------------ */
 
 
   /**
    * Normally, the file is deleted when this object passes out of scope. You
    * can set it to be preserved instead.
    *
    * @param bool True to preserve the file after object destruction.
    * @return this
    * @task config
    */
   public function setPreserveFile($preserve) {
     $this->preserve = $preserve;
     return $this;
   }
 
 
 /* -(  Internals  )---------------------------------------------------------- */
 
 
   /**
    * Get the path to the temporary file. Normally you can just use the object
    * in a string context.
    *
    * @return string Absolute path to the temporary file.
    * @task internal
    */
   public function __toString() {
     return $this->file;
   }
 
 
   /**
    * When the object is destroyed, it destroys the temporary file. You can
    * change this behavior with @{method:setPreserveFile}.
    *
    * @task internal
    */
   public function __destruct() {
+    if ($this->destroyed) {
+      return;
+    }
+
     if ($this->preserve) {
       return;
     }
+
     Filesystem::remove($this->dir);
 
     // NOTE: tempnam() doesn't guarantee it will return a file inside the
     // directory you passed to the function, so we make sure to nuke the file
     // explicitly.
 
     Filesystem::remove($this->file);
+
+    $this->file = null;
+    $this->dir = null;
+    $this->destroyed = true;
   }
 
 }