diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc
index 27d9576..bf44726 100644
--- a/core/includes/bootstrap.inc
+++ b/core/includes/bootstrap.inc
@@ -14,6 +14,7 @@
 use Drupal\Core\Extension\ExtensionDiscovery;
 use Drupal\Core\Logger\RfcLogLevel;
 use Drupal\Core\Session\AccountInterface;
+use Drupal\Core\DrupalStatic;
 use Drupal\Core\Site\Settings;
 use Drupal\Core\Utility\Error;
 use Symfony\Component\ClassLoader\ApcClassLoader;
@@ -865,146 +866,12 @@ function drupal_classloader_register($name, $path) {
 /**
  * Provides central static variable storage.
  *
- * All functions requiring a static variable to persist or cache data within
- * a single page request are encouraged to use this function unless it is
- * absolutely certain that the static variable will not need to be reset during
- * the page request. By centralizing static variable storage through this
- * function, other functions can rely on a consistent API for resetting any
- * other function's static variables.
- *
- * Example:
- * @code
- * function example_list($field = 'default') {
- *   $examples = &drupal_static(__FUNCTION__);
- *   if (!isset($examples)) {
- *     // If this function is being called for the first time after a reset,
- *     // query the database and execute any other code needed to retrieve
- *     // information.
- *     ...
- *   }
- *   if (!isset($examples[$field])) {
- *     // If this function is being called for the first time for a particular
- *     // index field, then execute code needed to index the information already
- *     // available in $examples by the desired field.
- *     ...
- *   }
- *   // Subsequent invocations of this function for a particular index field
- *   // skip the above two code blocks and quickly return the already indexed
- *   // information.
- *   return $examples[$field];
- * }
- * function examples_admin_overview() {
- *   // When building the content for the overview page, make sure to get
- *   // completely fresh information.
- *   drupal_static_reset('example_list');
- *   ...
- * }
- * @endcode
- *
- * In a few cases, a function can have certainty that there is no legitimate
- * use-case for resetting that function's static variable. This is rare,
- * because when writing a function, it's hard to forecast all the situations in
- * which it will be used. A guideline is that if a function's static variable
- * does not depend on any information outside of the function that might change
- * during a single page request, then it's ok to use the "static" keyword
- * instead of the drupal_static() function.
- *
- * Example:
- * @code
- * function mymodule_log_stream_handle($new_handle = NULL) {
- *   static $handle;
- *   if (isset($new_handle)) {
- *     $handle = $new_handle;
- *   }
- *   return $handle;
- * }
- * @endcode
- *
- * In a few cases, a function needs a resettable static variable, but the
- * function is called many times (100+) during a single page request, so
- * every microsecond of execution time that can be removed from the function
- * counts. These functions can use a more cumbersome, but faster variant of
- * calling drupal_static(). It works by storing the reference returned by
- * drupal_static() in the calling function's own static variable, thereby
- * removing the need to call drupal_static() for each iteration of the function.
- * Conceptually, it replaces:
- * @code
- * $foo = &drupal_static(__FUNCTION__);
- * @endcode
- * with:
- * @code
- * // Unfortunately, this does not work.
- * static $foo = &drupal_static(__FUNCTION__);
- * @endcode
- * However, the above line of code does not work, because PHP only allows static
- * variables to be initialized by literal values, and does not allow static
- * variables to be assigned to references.
- * - http://php.net/manual/language.variables.scope.php#language.variables.scope.static
- * - http://php.net/manual/language.variables.scope.php#language.variables.scope.references
- * The example below shows the syntax needed to work around both limitations.
- * For benchmarks and more information, see http://drupal.org/node/619666.
- *
- * Example:
- * @code
- * function example_default_format_type() {
- *   // Use the advanced drupal_static() pattern, since this is called very often.
- *   static $drupal_static_fast;
- *   if (!isset($drupal_static_fast)) {
- *     $drupal_static_fast['format_type'] = &drupal_static(__FUNCTION__);
- *   }
- *   $format_type = &$drupal_static_fast['format_type'];
- *   ...
- * }
- * @endcode
- *
- * @param $name
- *   Globally unique name for the variable. For a function with only one static,
- *   variable, the function name (e.g. via the PHP magic __FUNCTION__ constant)
- *   is recommended. For a function with multiple static variables add a
- *   distinguishing suffix to the function name for each one.
- * @param $default_value
- *   Optional default value.
- * @param $reset
- *   TRUE to reset one or all variables(s). This parameter is only used
- *   internally and should not be passed in; use drupal_static_reset() instead.
- *   (This function's return value should not be used when TRUE is passed in.)
- *
- * @return
- *   Returns a variable by reference.
- *
- * @see drupal_static_reset()
+ * @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.
+ *   Use \Drupal\Core\DrupalStatic::get().
  */
-function &drupal_static($name, $default_value = NULL, $reset = FALSE) {
-  static $data = array(), $default = array();
-  // First check if dealing with a previously defined static variable.
-  if (isset($data[$name]) || array_key_exists($name, $data)) {
-    // Non-NULL $name and both $data[$name] and $default[$name] statics exist.
-    if ($reset) {
-      // Reset pre-existing static variable to its default value.
-      $data[$name] = $default[$name];
-    }
-    return $data[$name];
-  }
-  // Neither $data[$name] nor $default[$name] static variables exist.
-  if (isset($name)) {
-    if ($reset) {
-      // Reset was called before a default is set and yet a variable must be
-      // returned.
-      return $data;
-    }
-    // First call with new non-NULL $name. Initialize a new static variable.
-    $default[$name] = $data[$name] = $default_value;
-    return $data[$name];
-  }
-  // Reset all: ($name == NULL). This needs to be done one at a time so that
-  // references returned by earlier invocations of drupal_static() also get
-  // reset.
-  foreach ($default as $name => $value) {
-    $data[$name] = $value;
-  }
-  // As the function returns a reference, the return should always be a
-  // variable.
-  return $data;
+function &drupal_static($name, $default_value = NULL) {
+  $value = &DrupalStatic::get($name, $default_value);
+  return $value;
 }
 
 /**
@@ -1012,11 +879,12 @@ function &drupal_static($name, $default_value = NULL, $reset = FALSE) {
  *
  * @param $name
  *   Name of the static variable to reset. Omit to reset all variables.
- *   Resetting all variables should only be used, for example, for running
- *   unit tests with a clean environment.
+ *
+ * @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.
+ *   Use \Drupal\Core\DrupalStatic::reset().
  */
 function drupal_static_reset($name = NULL) {
-  drupal_static($name, NULL, TRUE);
+  DrupalStatic::reset($name);
 }
 
 /**
diff --git a/core/lib/Drupal/Core/DrupalStatic.php b/core/lib/Drupal/Core/DrupalStatic.php
new file mode 100644
index 0000000..707f1c8
--- /dev/null
+++ b/core/lib/Drupal/Core/DrupalStatic.php
@@ -0,0 +1,179 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\DrupalStatic.
+ */
+
+namespace Drupal\Core;
+
+/**
+ * Provides central static variable storage.
+ *
+ * All functions requiring a static variable to persist or cache data within
+ * a single page request are encouraged to use this function unless it is
+ * absolutely certain that the static variable will not need to be reset during
+ * the page request. By centralizing static variable storage through this
+ * function, other functions can rely on a consistent API for resetting any
+ * other function's static variables.
+ *
+ * Example:
+ * @code
+ * function example_list($field = 'default') {
+ *   $examples = &drupal_static(__FUNCTION__);
+ *   if (!isset($examples)) {
+ *     // If this function is being called for the first time after a reset,
+ *     // query the database and execute any other code needed to retrieve
+ *     // information.
+ *     ...
+ *   }
+ *   if (!isset($examples[$field])) {
+ *     // If this function is being called for the first time for a particular
+ *     // index field, then execute code needed to index the information already
+ *     // available in $examples by the desired field.
+ *     ...
+ *   }
+ *   // Subsequent invocations of this function for a particular index field
+ *   // skip the above two code blocks and quickly return the already indexed
+ *   // information.
+ *   return $examples[$field];
+ * }
+ * function examples_admin_overview() {
+ *   // When building the content for the overview page, make sure to get
+ *   // completely fresh information.
+ *   drupal_static_reset('example_list');
+ *   ...
+ * }
+ * @endcode
+ *
+ * In a few cases, a function can have certainty that there is no legitimate
+ * use-case for resetting that function's static variable. This is rare,
+ * because when writing a function, it's hard to forecast all the situations in
+ * which it will be used. A guideline is that if a function's static variable
+ * does not depend on any information outside of the function that might change
+ * during a single page request, then it's ok to use the "static" keyword
+ * instead of the drupal_static() function.
+ *
+ * Example:
+ * @code
+ * function mymodule_log_stream_handle($new_handle = NULL) {
+ *   static $handle;
+ *   if (isset($new_handle)) {
+ *     $handle = $new_handle;
+ *   }
+ *   return $handle;
+ * }
+ * @endcode
+ *
+ * In a few cases, a function needs a resettable static variable, but the
+ * function is called many times (100+) during a single page request, so
+ * every microsecond of execution time that can be removed from the function
+ * counts. These functions can use a more cumbersome, but faster variant of
+ * calling drupal_static(). It works by storing the reference returned by
+ * drupal_static() in the calling function's own static variable, thereby
+ * removing the need to call drupal_static() for each iteration of the function.
+ * Conceptually, it replaces:
+ * @code
+ * $foo = &drupal_static(__FUNCTION__);
+ * @endcode
+ * with:
+ * @code
+ * // Unfortunately, this does not work.
+ * static $foo = &drupal_static(__FUNCTION__);
+ * @endcode
+ * However, the above line of code does not work, because PHP only allows static
+ * variables to be initializied by literal values, and does not allow static
+ * variables to be assigned to references.
+ * - http://php.net/manual/language.variables.scope.php#language.variables.scope.static
+ * - http://php.net/manual/language.variables.scope.php#language.variables.scope.references
+ * The example below shows the syntax needed to work around both limitations.
+ * For benchmarks and more information, see http://drupal.org/node/619666.
+ *
+ * Example:
+ * @code
+ * function user_access($string, $account = NULL) {
+ *   // Use the advanced drupal_static() pattern, since this is called very often.
+ *   static $drupal_static_fast;
+ *   if (!isset($drupal_static_fast)) {
+ *     $drupal_static_fast['perm'] = &drupal_static(__FUNCTION__);
+ *   }
+ *   $perm = &$drupal_static_fast['perm'];
+ *   ...
+ * }
+ * @endcode
+ */
+class DrupalStatic {
+
+  /**
+   * An array keyed by variable name containing the current values for each.
+   * @var array
+   */
+  protected static $data = array();
+
+  /**
+   * An array of known default values, keyed by variable name.
+   *
+   * @var array
+   */
+  protected static $default = array();
+
+  /**
+   * Gets the value for a specified name.
+   *
+   * @param string|null $name
+   *   Globally unique name for the variable. For a function with only one
+   *   static, variable, the function name (e.g. via the PHP magic __FUNCTION__
+   *   constant) is recommended. For a function with multiple static variables
+   *   add a distinguishing suffix to the function name for each one. If NULL is
+   *   passed, the entire contents of self::$data will be replaced with known
+   *   default values and then returned.
+   * @param mixed $default_value
+   *   (optional) A default value, defaults to NULL.
+   *
+   * @return mixed
+   *   Returns a variable by reference.
+   *
+   * @see drupal_static_reset()
+   */
+  public static function &get($name, $default_value = NULL) {
+    // First check if dealing with a previously defined static variable.
+    if (isset(static::$data[$name]) || array_key_exists($name, static::$data)) {
+      // Non-NULL $name and both static::$data[$name] and
+      // static::$default[$name] statics exist.
+      return static::$data[$name];
+    }
+    // Neither static::$data[$name] nor static::$default[$name] static variables
+    // exist.
+    if (isset($name)) {
+      // First call with new non-NULL $name. Initialize a new static variable.
+      static::$default[$name] = static::$data[$name] = $default_value;
+      return static::$data[$name];
+    }
+    // As the function returns a reference, the return should always be a
+    // variable.
+    return static::$data;
+  }
+
+  /**
+   * Resets one or all centrally stored static variable(s).
+   *
+   * @param string|null $name
+   *   (optional) The name of the variable to reset. If NULL, all variables will
+   *   be reset.
+   */
+  public static function reset($name = NULL) {
+    if (!isset($name)) {
+      // Reset all: ($name == NULL). This needs to be done one at a time so that
+      // references returned by earlier invocations of drupal_static() also get
+      // reset.
+      foreach (static::$default as $name => $value) {
+        static::$data[$name] = $value;
+      }
+    }
+    elseif (isset(static::$data[$name]) || array_key_exists($name, static::$data)) {
+      // Reset pre-existing static variable to its default value.
+      static::$data[$name] = static::$default[$name];
+    }
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Form/FormBuilder.php b/core/lib/Drupal/Core/Form/FormBuilder.php
index b67a37b..fe61674 100644
--- a/core/lib/Drupal/Core/Form/FormBuilder.php
+++ b/core/lib/Drupal/Core/Form/FormBuilder.php
@@ -14,6 +14,7 @@
 use Drupal\Component\Utility\UrlHelper;
 use Drupal\Core\Access\CsrfTokenGenerator;
 use Drupal\Core\DependencyInjection\ClassResolverInterface;
+use Drupal\Core\DrupalStatic;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Render\Element;
 use Drupal\Core\Theme\ThemeManagerInterface;
@@ -475,6 +476,7 @@ public function processForm($form_id, &$form, FormStateInterface &$form_state) {
       if (!FormState::hasAnyErrors()) {
         // In case of errors, do not break HTML IDs of other forms.
         Html::resetSeenIds();
+        DrupalStatic::reset('drupal_html_id');
       }
 
       if (!$form_state->isRebuilding() && !FormState::hasAnyErrors()) {
@@ -1088,6 +1090,33 @@ protected function getElementInfo($type) {
   }
 
   /**
+   * Wraps drupal_installation_attempted().
+   *
+   * @return bool
+   */
+  protected function drupalInstallationAttempted() {
+    return drupal_installation_attempted();
+  }
+
+  /**
+   * Wraps drupal_html_class().
+   *
+   * @return string
+   */
+  protected function drupalHtmlClass($class) {
+    return drupal_html_class($class);
+  }
+
+  /**
+   * Wraps drupal_html_id().
+   *
+   * @return string
+   */
+  protected function drupalHtmlId($id) {
+    return drupal_html_id($id);
+  }
+
+  /**
    * Gets the current active user.
    *
    * @return \Drupal\Core\Session\AccountInterface
diff --git a/core/tests/Drupal/Tests/Core/DrupalStaticTest.php b/core/tests/Drupal/Tests/Core/DrupalStaticTest.php
new file mode 100644
index 0000000..66155b0
--- /dev/null
+++ b/core/tests/Drupal/Tests/Core/DrupalStaticTest.php
@@ -0,0 +1,94 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Tests\Core\DrupalStaticTest.
+ */
+
+namespace Drupal\Tests\Core;
+
+use Drupal\Core\DrupalStatic;
+use Drupal\Tests\UnitTestCase;
+
+/**
+ * @coversDefaultClass \Drupal\Core\DrupalStatic
+ *
+ * @group Drupal
+ */
+class DrupalStaticTest extends UnitTestCase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Tests \Drupal\Core\DrupalStatic',
+      'description' => '',
+      'group' => 'Bootstrap',
+    );
+  }
+  protected function tearDown() {
+    parent::tearDown();
+    $empty = &DrupalStatic::get(NULL);
+    $empty = array();
+  }
+
+  /**
+   * @covers ::get
+   */
+  public function testGet() {
+    $var1 = &DrupalStatic::get(__METHOD__, 'foo');
+    $this->assertSame('foo', $var1);
+  }
+
+  /**
+   * @covers ::get
+   */
+  public function testGetRepeated() {
+    $var1 = &DrupalStatic::get(__METHOD__, 'foo');
+    $this->assertSame('foo', $var1);
+
+    $var1 = 'bar';
+    $var2 = &DrupalStatic::get(__METHOD__, 'foo');
+    $this->assertSame('bar', $var2);
+  }
+
+  /**
+   * @covers ::get
+   */
+  public function testGetNull() {
+    $var1 = &DrupalStatic::get(NULL);
+    $this->assertSame(array(), $var1);
+
+    $var2 = &DrupalStatic::get(__METHOD__, 'foo');
+    $expected = array(
+      __METHOD__ => $var2,
+    );
+    $this->assertSame($expected, $var1);
+  }
+
+  /**
+   * @covers ::reset
+   */
+  public function testReset() {
+    $var1 = &DrupalStatic::get(__METHOD__, 'foo');
+    $this->assertSame('foo', $var1);
+
+    $var1 = 'bar';
+    DrupalStatic::reset(__METHOD__);
+    $this->assertSame('foo', $var1);
+  }
+
+  /**
+   * @covers ::reset
+   */
+  public function testResetNull() {
+    $var1 = &DrupalStatic::get(__METHOD__, 'foo');
+    $this->assertSame('foo', $var1);
+    $var1 = 'bar';
+
+    DrupalStatic::reset();
+    $this->assertSame('foo', $var1);
+  }
+
+}
diff --git a/core/tests/Drupal/Tests/Core/Form/FormTestBase.php b/core/tests/Drupal/Tests/Core/Form/FormTestBase.php
index 2386eb2..ee1c5be 100644
--- a/core/tests/Drupal/Tests/Core/Form/FormTestBase.php
+++ b/core/tests/Drupal/Tests/Core/Form/FormTestBase.php
@@ -5,9 +5,10 @@
  * Contains \Drupal\Tests\Core\Form\FormTestBase.
  */
 
-namespace Drupal\Tests\Core\Form {
+namespace Drupal\Tests\Core\Form;
 
 use Drupal\Component\Utility\Html;
+use Drupal\Core\DrupalStatic;
 use Drupal\Core\Form\FormBuilder;
 use Drupal\Core\Form\FormInterface;
 use Drupal\Core\Form\FormStateInterface;
@@ -17,6 +18,7 @@
 use Symfony\Component\HttpFoundation\RequestStack;
 use Symfony\Component\HttpFoundation\Response;
 
+
 /**
  * Provides a base class for testing form functionality.
  *
@@ -171,6 +173,17 @@ protected function setUp() {
    */
   protected function tearDown() {
     Html::resetSeenIds();
+    DrupalStatic::reset('drupal_html_id');
+  }
+
+  /**
+   * Sets up a new form builder object to test.
+   */
+  protected function setupFormBuilder() {
+    $request_stack = new RequestStack();
+    $request_stack->push($this->request);
+    $this->formBuilder = new TestFormBuilder($this->formValidator, $this->moduleHandler, $this->keyValueExpirableFactory, $this->eventDispatcher, $this->urlGenerator, $request_stack, $this->csrfToken, $this->httpKernel);
+    $this->formBuilder->setCurrentUser($this->account);
   }
 
   /**
@@ -312,11 +325,12 @@ protected function drupalHtmlClass($class) {
    * {@inheritdoc}
    */
   protected function drupalHtmlId($id) {
-    if (isset(static::$seenIds[$id])) {
-      $id = $id . '--' . ++static::$seenIds[$id];
+    $seen_ids = &DrupalStatic::get('drupal_html_id', array());
+    if (isset($seen_ids[$id])) {
+      $id = $id . '--' . ++$seen_ids[$id];
     }
     else {
-      static::$seenIds[$id] = 1;
+      $seen_ids[$id] = 1;
     }
     return $id;
   }
@@ -335,36 +349,12 @@ protected function requestUri() {
     return '';
   }
 
-}
-
-}
-
-namespace {
-
-  function test_form_id() {
-    $form['test'] = array(
-      '#type' => 'textfield',
-      '#title' => 'Test',
-    );
-    $form['options'] = array(
-      '#type' => 'radios',
-      '#options' => array(
-        'foo' => 'foo',
-        'bar' => 'bar',
-      ),
-    );
-    $form['value'] = array(
-      '#type' => 'value',
-      '#value' => 'bananas',
-    );
-    $form['actions'] = array(
-      '#type' => 'actions',
-    );
-    $form['actions']['submit'] = array(
-      '#type' => 'submit',
-      '#value' => 'Submit',
-    );
-    return $form;
+  /**
+   * {@inheritdoc}
+   */
+  protected function &batchGet() {
+    $batch = array();
+    return $batch;
   }
 
 }
