Native Namespace Code Prep #1721

Closed
wants to merge 6 commits into
from
Jump to file
+657 −591
Split
@@ -0,0 +1,62 @@
+## Namespacing
+
+This chapter outlines things to remember when dealing with namespacing. Full native namespacing has not yet been implemented in the Joomla! Platform. So far, there are some preparations being made to make the transition, but we are a long way from making that large change.
+
+
+### Things to Remember When Contributing
+
+When writing code to contribute back to the platform, there are some things to keep in mind.
+
+* Preface internal PHP or SPL classes with a backslash. This tells PHP to search the global namespace. More information here: [Using Global Classes in Namespaces on php.net](http://www.php.net/manual/en/language.namespaces.faq.php#language.namespaces.faq.globalclass)
+
+```php
+/**
+ * This is the wrong way to call the class.
+ * When full namespacing is achieved, this
+ * will result in a class load error.
+ * Ex. "Class \Foo\Bar\stdClass not found"
+ */
+$obj = new stdClass;
+$obj->property = 'foo';
+
+/**
+ * Same when working with Exceptions. This
+ * will fail in a fully namespaced environment.
+ */
+throw new RuntimeException('Error Message Here.');
+
+/**
+ * This is the correct way to call it. The
+ * The forward slash tells it to search for
+ * the class in the global namespace
+ */
+$obj = new \stdClass;
+$obj->property = 'bar';
+
+// And Exceptions
+throw new \RuntimeException('Yay namespaces!')
+```
+
+* Calls to included libraries must also follow proper namespacing rules. If you wanted to use the `PDO` classes, you'll need to preface that with a backslash as well.
+
+```php
+\PDO::query();
+```
+
+* When using callables, use the magic `__CLASS__` constant whenever possible. For example, in `JLoader` we call `spl_autoload_register()` several times. This function takes a callable as it's argument, which is passed as an array of class name and method name. (See example below.) The reason this is important is that the `__CLASS__` constant returns the calling class name. If that class is in a namespace, it returns the fully qualified class name. This means the code you write in this fashion will not need to be re-written when full namespacing is achieved. It will just work. More information here: [`__CLASS__` on php.net](http://php.net/manual/en/language.constants.predefined.php)
+
+```php
+// This is the old way
+spl_autoload_register(array('JLoader', 'load'));
+
+// This is the namespaced way
+spl_autoload_register(array(__CLASS__, 'load'));
+```
+
+### Namespace Compatibility Layer
+
+When full namespacing is achieved, there will be a compatibility layer that you can enable. This will allow you to use the latest platform code base with your existing app, without requiring a full re-write. By allowing users to make the transition as time allows, we reduce headaches without reducing our user base. All type hinting, `is_subclass_of()`, `instanceof`, etc continues to work with this approach as well. It's much more seamless than importing all the classes at the top of each file where they are used.
+
+This compatibility layer will consist of basically a class map that will use the `class_alias` function to create aliases to all the class names as they exist now. One of the bigger benefits of this approach is that it requires little interaction from the end-user/developer. Simply enable the compatibility later, and your app will continue to function as it always has (in theory).
+
+This layer will be available at least for 2 platform releases after achieving full namespace compatibility, after which it may be retained by any applications that are using it, such as the CMS if it chooses to implement these changes.
@@ -20,6 +20,7 @@
- [Basic Guidelines](coding-standards/chapters/basic-guidelines.md)
- [Comments](coding-standards/chapters/comments.md)
- [PHP Code](coding-standards/chapters/php.md)
+- [Namespacing](coding-standards/chapters/namespacing.md)
- Appendices
- [Code Analysis](appendices/analysis.md)
@@ -488,7 +488,7 @@ public static function getActionsFromFile($file, $xpath = "/access/section[@name
public static function getActionsFromData($data, $xpath = "/access/section[@name='component']/")
{
// If the data to load isn't already an XML element or string return false.
- if ((!($data instanceof SimpleXMLElement)) && (!is_string($data)))
+ if ((!($data instanceof \SimpleXMLElement)) && (!is_string($data)))
{
return false;
}
@@ -498,7 +498,7 @@ public static function getActionsFromData($data, $xpath = "/access/section[@name
{
try
{
- $data = new SimpleXMLElement($data);
+ $data = new \SimpleXMLElement($data);
}
catch (Exception $e)
{
@@ -126,13 +126,13 @@ public static function getInstance($name = null)
// Only create the object if it doesn't exist.
if (empty(self::$instance))
{
- if (class_exists($name) && (is_subclass_of($name, 'JApplicationCli')))
+ if (class_exists($name) && (is_subclass_of($name, __CLASS__)))
{
self::$instance = new $name;
}
else
{
- self::$instance = new JApplicationCli;
+ self::$instance = new static;
}
}
@@ -271,7 +271,7 @@ protected function fetchConfigurationData($file = '', $class = 'JConfig')
}
else
{
- throw new RuntimeException('Configuration class does not exist.');
+ throw new \RuntimeException('Configuration class does not exist.');
}
}
@@ -114,14 +114,14 @@ public function __construct(JInputCli $input = null, JRegistry $config = null, J
if (!defined('SIGHUP'))
{
JLog::add('The PCNTL extension for PHP is not available.', JLog::ERROR);
- throw new RuntimeException('The PCNTL extension for PHP is not available.');
+ throw new \RuntimeException('The PCNTL extension for PHP is not available.');
}
// Verify that POSIX support for PHP is available.
if (!function_exists('posix_getpid'))
{
JLog::add('The POSIX extension for PHP is not available.', JLog::ERROR);
- throw new RuntimeException('The POSIX extension for PHP is not available.');
+ throw new \RuntimeException('The POSIX extension for PHP is not available.');
}
// @codeCoverageIgnoreEnd
@@ -157,10 +157,10 @@ public static function signal($signal)
JLog::add('Received signal: ' . $signal, JLog::DEBUG);
// Let's make sure we have an application instance.
- if (!is_subclass_of(static::$instance, 'JApplicationDaemon'))
+ if (!is_subclass_of(static::$instance, __CLASS__))
{
JLog::add('Cannot find the application instance.', JLog::EMERGENCY);
- throw new RuntimeException('Cannot find the application instance.');
+ throw new \RuntimeException('Cannot find the application instance.');
}
// Fire the onReceiveSignal event.
@@ -535,7 +535,7 @@ protected function daemonize()
$this->parentId = $this->processId;
}
}
- catch (RuntimeException $e)
+ catch (\RuntimeException $e)
{
JLog::add('Unable to fork.', JLog::EMERGENCY);
@@ -641,7 +641,7 @@ protected function fork()
// If the fork failed, throw an exception.
if ($pid === -1)
{
- throw new RuntimeException('The process could not be forked.');
+ throw new \RuntimeException('The process could not be forked.');
}
// Update the process id for the child.
elseif ($pid === 0)
@@ -706,7 +706,7 @@ protected function setupSignalHandlers()
}
// Attach the signal handler for the signal.
- if (!$this->pcntlSignal(constant($signal), array('JApplicationDaemon', 'signal')))
+ if (!$this->pcntlSignal(constant($signal), array(__CLASS__, 'signal')))
{
JLog::add(sprintf('Unable to reroute signal handler: %s', $signal), JLog::EMERGENCY);
@@ -149,7 +149,7 @@ public static function getInstance($client, $options = array())
}
else
{
- throw new RuntimeException(JText::sprintf('JLIB_APPLICATION_ERROR_ROUTER_LOAD', $client), 500);
+ throw new \RuntimeException(JText::sprintf('JLIB_APPLICATION_ERROR_ROUTER_LOAD', $client), 500);
}
}
@@ -136,7 +136,7 @@ public function __construct(JInput $input = null, JRegistry $config = null, JApp
$this->set('execution.timestamp', time());
// Setup the response object.
- $this->response = new stdClass;
+ $this->response = new \stdClass;
$this->response->cachable = false;
$this->response->headers = array();
$this->response->body = array();
@@ -161,13 +161,13 @@ public static function getInstance($name = null)
// Only create the object if it doesn't exist.
if (empty(self::$instance))
{
- if (class_exists($name) && (is_subclass_of($name, 'JApplicationWeb')))
+ if (class_exists($name) && (is_subclass_of($name, __CLASS__)))
{
self::$instance = new $name;
}
else
{
- self::$instance = new JApplicationWeb;
+ self::$instance = new static;
}
}
@@ -920,7 +920,7 @@ protected function fetchConfigurationData($file = '', $class = 'JConfig')
}
else
{
- throw new RuntimeException('Configuration class does not exist.');
+ throw new \RuntimeException('Configuration class does not exist.');
}
}
@@ -142,7 +142,7 @@ protected function fetchController($name)
// If the controller class does not exist panic.
if (!class_exists($class) || !is_subclass_of($class, 'JController'))
{
- throw new RuntimeException(sprintf('Unable to locate controller `%s`.', $class), 404);
+ throw new \RuntimeException(sprintf('Unable to locate controller `%s`.', $class), 404);
}
// Instantiate the controller.
@@ -169,7 +169,7 @@ protected function parseRoute($route)
// We were unable to find a route match for the request. Panic.
if (!$controller)
{
- throw new InvalidArgumentException(sprintf('Unable to handle request for route `%s`.', $route), 404);
+ throw new \InvalidArgumentException(sprintf('Unable to handle request for route `%s`.', $route), 404);
}
return $controller;
@@ -121,7 +121,7 @@ protected function fetchControllerSuffix()
// Validate that we have a map to handle the given HTTP method.
if (!isset($this->suffixMap[$this->input->getMethod()]))
{
- throw new RuntimeException(sprintf('Unable to support the HTTP method `%s`.', $this->input->getMethod()), 404);
+ throw new \RuntimeException(sprintf('Unable to support the HTTP method `%s`.', $this->input->getMethod()), 404);
}
// Check if request method is POST
@@ -128,7 +128,7 @@ public static function extract($archivename, $extractdir)
$tmpfname = $config->get('tmp_path') . '/' . uniqid('bzip2');
$bzresult = $adapter->extract($archivename, $tmpfname);
- if ($bzresult instanceof Exception)
+ if ($bzresult instanceof \Exception)
{
@unlink($tmpfname);
@@ -157,10 +157,10 @@ public static function extract($archivename, $extractdir)
break;
default:
- throw new InvalidArgumentException('Unknown Archive Type');
+ throw new \InvalidArgumentException('Unknown Archive Type');
}
- if (!$result || $result instanceof Exception)
+ if (!$result || $result instanceof \Exception)
{
return false;
}
@@ -187,7 +187,7 @@ public static function getAdapter($type)
if (!class_exists($class))
{
- throw new UnexpectedValueException('Unable to load archive', 500);
+ throw new \UnexpectedValueException('Unable to load archive', 500);
}
self::$adapters[$type] = new $class;
@@ -52,7 +52,7 @@ public function extract($archive, $destination, array $options = array ())
}
else
{
- throw new RuntimeException('The bz2 extension is not available.');
+ throw new \RuntimeException('The bz2 extension is not available.');
}
}
@@ -69,7 +69,7 @@ public function extract($archive, $destination, array $options = array ())
}
else
{
- throw new RuntimeException('Unable to read archive');
+ throw new \RuntimeException('Unable to read archive');
}
}
@@ -84,7 +84,7 @@ public function extract($archive, $destination, array $options = array ())
}
else
{
- throw new RuntimeException('Unable to decompress data');
+ throw new \RuntimeException('Unable to decompress data');
}
}
@@ -96,7 +96,7 @@ public function extract($archive, $destination, array $options = array ())
}
else
{
- throw new RuntimeException('Unable to write archive');
+ throw new \RuntimeException('Unable to write archive');
}
}
@@ -117,7 +117,7 @@ public function extract($archive, $destination, array $options = array ())
}
else
{
- throw new RuntimeException('Unable to read archive (bz2)');
+ throw new \RuntimeException('Unable to read archive (bz2)');
}
}
@@ -133,7 +133,7 @@ public function extract($archive, $destination, array $options = array ())
}
else
{
- throw new RuntimeException('Unable to write archive (bz2)');
+ throw new \RuntimeException('Unable to write archive (bz2)');
}
}
@@ -153,7 +153,7 @@ public function extract($archive, $destination, array $options = array ())
}
else
{
- throw new RuntimeException('Unable to write archive (bz2)');
+ throw new \RuntimeException('Unable to write archive (bz2)');
}
}
}
Oops, something went wrong.