* @copyright 2012 Hans-Peter Buniat * @license http://opensource.org/licenses/BSD-3-Clause */ class namespaceRefactor { /** * The found files * * @var array */ protected $_aFiles = array(); /** * The found classes * * @var array */ protected $_aClasses = array(); /** * Write the results to the file or just dump the changes * * @var bool */ protected $_bWrite = false; /** * The directory where we're looking for files * * @var string */ protected $_sDirectory = ''; /** * An optional prefix * * @var string */ protected $_sPrefix; /** * Create * * @param array $aOpts */ public function __construct(array $aOpts) { $this->_sDirectory = $aOpts['d']; $this->_sPrefix = $aOpts['p']; if ($aOpts['w'] === 'true') { $this->_bWrite = true; } } /** * Get all php-files from the given directory * * @return namespaceRefactor */ public function getFiles() { $oIterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($this->_sDirectory)); $aSuffixes = array( 'php' ); $sRegex = '/^.+\.(' . implode('|', $aSuffixes) . ')$/i'; $oFiles = new RegexIterator($oIterator, $sRegex, RecursiveRegexIterator::GET_MATCH); $this->_aFiles = array(); foreach($oFiles as $aFile) { $this->_aFiles[] = $aFile[0]; } return $this; } /** * Parse all files and find class-declarations * - If a file does contain a namespace declaration, the class-declaration should not be converted * * @return namespaceRefactor */ public function readClasses() { $aFiles = array(); foreach ($this->_aFiles as $sFile) { $aFiles[$sFile] = array(); $aTokens = token_get_all(file_get_contents($sFile)); $aFound = array(); $bLocked = $bClassFound = false; foreach ($aTokens as $aToken) { $sType = is_array($aToken) ? $aToken[0] : null; $sData = (string) (is_array($aToken) ? $aToken[1] : $aToken); if ($bLocked === false and $bClassFound === true and $sType === T_STRING) { $this->_aClasses[$sData] = $sData; $aFound[] = $sData; $aFiles[$sFile] = $sData; $bClassFound = false; } if ($sType === T_CLASS or $sType === T_INTERFACE) { $bClassFound = true; } // ensure, that classes which are already namespaced are not replaced again if ($sType === T_NAMESPACE) { $bLocked = true; foreach ($aFound as $sFoundClass) { if (empty($this->_aClasses[$sFoundClass]) !== true) { unset($this->_aClasses[$sFoundClass]); } } } } } $this->_aFiles = $aFiles; return $this; } /** * Create the new namespace class for all found classes * * @return namespaceRefactor */ public function getNamespaces() { $aClasses = array(); foreach ($this->_aClasses as $sClass) { $aClass = explode('_', $sClass); if (count($aClass) > 1 or empty($this->_sPrefix) !== true) { $sNewClass = array_pop($aClass); $sNamespace = (count($aClass) > 1) ? sprintf('\%s', implode('\\', $aClass)): ''; $aClasses[$sClass] = array( 'class' => $sNewClass, 'namespace' => $sNamespace ); if (empty($this->_sPrefix) !== true) { $iLenght = strlen($this->_sPrefix); if (substr($aClasses[$sClass]['namespace'], 1, $iLenght) !== $this->_sPrefix) { $aClasses[$sClass]['namespace'] = sprintf('\%s%s', $this->_sPrefix, $aClasses[$sClass]['namespace']); } } } } $this->_aClasses = $aClasses; return $this; } /** * Replace the declarations * * @return void */ public function replace() { foreach ($this->_aFiles as $sFile => $sClass) { $sContent = file_get_contents($sFile); $sCompare = $sContent; if (empty($sClass) !== true and empty($this->_aClasses[$sClass]) !== true) { $aContent = explode(' */', $sContent); $aContent[1] = sprintf('%snamespace %s;%s%s',PHP_EOL, substr($this->_aClasses[$sClass]['namespace'], 1), PHP_EOL, $aContent[1]); $sContent = implode(' */', $aContent); } foreach ($this->_aClasses as $sFindClass => $aReplace) { $sReplace = ($sClass === $sFindClass) ? $aReplace['class'] : sprintf('%s\%s', $aReplace['namespace'], $aReplace['class']); $sContent = str_replace($sFindClass, $sReplace, $sContent); } if ($sCompare !== $sContent) { if ($this->_bWrite === true) { file_put_contents($sFile, $sContent); } else { print_r(sprintf('%s:%s%s', $sFile, PHP_EOL, $sContent)); } } } } } $aOpts = getopt('d:w:p:'); if (empty($aOpts['d']) === true) { print_r('usage: ' . $argv[0] . ' -p prefix -d directory -w [false|true]' . PHP_EOL); exit; } if (empty($aOpts['w']) === true) { $aOpts['w'] = 'false'; } $o = new namespaceRefactor($aOpts); $o->getFiles()->readClasses()->getNamespaces()->replace();