public function init($properties = array()) {
        // Set all the defined properties
        foreach ($properties as $name => $value) {
            $this->$name = $value;
        }

        // Get the requested URL without the base directory
        if ($this->base != '/' && strlen($this->base) > 0 && strpos($this->url, $this->base) === 0) {
            $this->url = substr($this->url, strlen($this->base));
        }

        // Default url
        if (empty($this->url)) {
            $this->url = '/';
        }
        // Merge URL query parameters with $_GET
        else {
            $_GET += self::parseQuery($this->url);

            $this->query->setData($_GET);
        }

        // Check for JSON input
        if (strpos($this->type, 'application/json') === 0) {
            $body = $this->getBody();
            if ($body != '') {
                $data = json_decode($body, true);
                if ($data != null) {
                    $this->data->setData($data);
                }
            }
        }
    }

Initialize request properties.

@param array $properties Array of request properties


public static function getBody() {
        static $body;

        if (!is_null($body)) {
            return $body;
        }

        $method = self::getMethod();

        if ($method == 'POST' || $method == 'PUT' || $method == 'PATCH') {
            $body = file_get_contents('php://input');
        }

        return $body;
    }

public static function getBody ( ) { static $ body ; if ( ! is_null ( $ body ) ) { return $ body ; } $ method = self :: getMethod ( ) ; if ( $ method == 'POST' || $ method == 'PUT' || $ method == 'PATCH' ) { $ body = file_get_contents ( 'php://input' ) ; } return $ body ; }

Gets the body of the request.

@return string Raw HTTP request body


public static function getMethod() {
        $method = self::getVar('REQUEST_METHOD', 'GET');

        if (isset($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'])) {
            $method = $_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'];
        }
        elseif (isset($_REQUEST['_method'])) {
            $method = $_REQUEST['_method'];
        }

        return strtoupper($method);
    }

public static function getMethod ( ) { $ method = self :: getVar ( 'REQUEST_METHOD' , 'GET' ) ; if ( isset ( $ _SERVER [ 'HTTP_X_HTTP_METHOD_OVERRIDE' ] ) ) { $ method = $ _SERVER [ 'HTTP_X_HTTP_METHOD_OVERRIDE' ] ; } elseif ( isset ( $ _REQUEST [ '_method' ] ) ) { $ method = $ _REQUEST [ '_method' ] ; } return strtoupper ( $ method ) ; }

Gets the request method.

@return string


public static function getProxyIpAddress() {
        static $forwarded = array(
            'HTTP_CLIENT_IP',
            'HTTP_X_FORWARDED_FOR',
            'HTTP_X_FORWARDED',
            'HTTP_X_CLUSTER_CLIENT_IP',
            'HTTP_FORWARDED_FOR',
            'HTTP_FORWARDED'
        );

        $flags = \FILTER_FLAG_NO_PRIV_RANGE | \FILTER_FLAG_NO_RES_RANGE;

        foreach ($forwarded as $key) {
            if (array_key_exists($key, $_SERVER)) {
                sscanf($_SERVER[$key], '%[^,]', $ip);
                if (filter_var($ip, \FILTER_VALIDATE_IP, $flags) !== false) {
                    return $ip;
                }
            }
        }

        return '';
    }

public static function getProxyIpAddress ( ) { static $ forwarded = array ( 'HTTP_CLIENT_IP' , 'HTTP_X_FORWARDED_FOR' , 'HTTP_X_FORWARDED' , 'HTTP_X_CLUSTER_CLIENT_IP' , 'HTTP_FORWARDED_FOR' , 'HTTP_FORWARDED' ) ; $ flags = \ FILTER_FLAG_NO_PRIV_RANGE | \ FILTER_FLAG_NO_RES_RANGE ; foreach ( $ forwarded as $ key ) { if ( array_key_exists ( $ key , $ _SERVER ) ) { sscanf ( $ _SERVER [ $ key ] , '%[^,]' , $ ip ) ; if ( filter_var ( $ ip , \ FILTER_VALIDATE_IP , $ flags ) !== false ) { return $ ip ; } } } return '' ; }

Gets the real remote IP address.

@return string IP address


public static function parseQuery($url) {
        $params = array();

        $args = parse_url($url);
        if (isset($args['query'])) {
            parse_str($args['query'], $params);
        }

        return $params;
    }

public static function parseQuery ( $ url ) { $ params = array ( ) ; $ args = parse_url ( $ url ) ; if ( isset ( $ args [ 'query' ] ) ) { parse_str ( $ args [ 'query' ] , $ params ) ; } return $ params ; }

Parse query parameters from a URL.

@param string $url URL string
@return array Query parameters


public function status($code = null) {
        if ($code === null) {
            return $this->status;
        }

        if (array_key_exists($code, self::$codes)) {
            $this->status = $code;
        }
        else {
            throw new \Exception('Invalid status code.');
        }

        return $this;
    }

public
function
status
(
$
code
=
)
{
if
(
$
code
===
)
{
return
$
this
->
status
;
}
if
(
array_key_exists
(
$
code
,
self
::
$
codes
)
)
{
$
this
->
status
=
$
code
;
}
else
{
throw
new
\
Exception
(
'Invalid status code.'
)
;
}
return
$
this
;
}

Sets the HTTP status of the response.

@param int $code HTTP status code.
@return object|int Self reference
@throws \Exception If invalid status code


public function header($name, $value = null) {
        if (is_array($name)) {
            foreach ($name as $k => $v) {
                $this->headers[$k] = $v;
            }
        }
        else {
            $this->headers[$name] = $value;
        }

        return $this;
    }

public function header ( $ name , $ value = null ) { if ( is_array ( $ name ) ) { foreach ( $ name as $ k => $ v ) { $ this -> headers [ $ k ] = $ v ; } } else { $ this -> headers [ $ name ] = $ value ; } return $ this ; }

Adds a header to the response.

@param string|array $name Header name or array of names and values
@param string $value Header value
@return object Self reference


public function cache($expires) {
        if ($expires === false) {
            $this->headers['Expires'] = 'Mon, 26 Jul 1997 05:00:00 GMT';
            $this->headers['Cache-Control'] = array(
                'no-store, no-cache, must-revalidate',
                'post-check=0, pre-check=0',
                'max-age=0'
            );
            $this->headers['Pragma'] = 'no-cache';
        }
        else {
            $expires = is_int($expires) ? $expires : strtotime($expires);
            $this->headers['Expires'] = gmdate('D, d M Y H:i:s', $expires) . ' GMT';
            $this->headers['Cache-Control'] = 'max-age='.($expires - time());
            if (isset($this->headers['Pragma']) && $this->headers['Pragma'] == 'no-cache'){
                unset($this->headers['Pragma']);
            }
        }
        return $this;
    }

public
function
cache
(
$
expires
)
{
if
(
$
expires
===
false
)
{
$
this
->
headers
[
'Expires'
]
=
'Mon, 26 Jul 1997 05:00:00 GMT'
;
$
this
->
headers
[
'Cache-Control'
]
=
array
(
'no-store, no-cache, must-revalidate'
,
'post-check=0, pre-check=0'
,
'max-age=0'
)
;
$
this
->
headers
[
'Pragma'
]
=
'no-cache'
;
}
else
{
$
expires
=
is_int
(
$
expires
)
$
expires
:
strtotime
(
$
expires
)
;
$
this
->
headers
[
'Expires'
]
=
gmdate
(
'D, d M Y H:i:s'
,
$
expires
)
.
' GMT'
;
$
this
->
headers
[
'Cache-Control'
]
=
'max-age='
.
(
$
expires
time
(
)
)
;
if
(
isset
(
$
this
->
headers
[
'Pragma'
]
)
&&
$
this
->
headers
[
'Pragma'
]
==
'no-cache'
)
{
unset
(
$
this
->
headers
[
'Pragma'
]
)
;
}
}
return
$
this
;
}

Sets caching headers for the response.

@param int|string $expires Expiration time
@return object Self reference


public function send() {
        if (ob_get_length() > 0) {
            ob_end_clean();
        }

        if (!headers_sent()) {
            $this->sendHeaders();
        }

        echo $this->body;

        $this->sent = true;
    }

public function send ( ) { if ( ob_get_length ( ) > 0 ) { ob_end_clean ( ) ; } if ( ! headers_sent ( ) ) { $ this -> sendHeaders ( ) ; } echo $ this -> body ; $ this -> sent = true ; }


public function init() {
        static $initialized = false;
        $self = $this;

        if ($initialized) {
            $this->vars = array();
            $this->loader->reset();
            $this->dispatcher->reset();
        }

        // Register default components
        $this->loader->register('request', '\flight\net\Request');
        $this->loader->register('response', '\flight\net\Response');
        $this->loader->register('router', '\flight\net\Router');
        $this->loader->register('view', '\flight\template\View', array(), function($view) use ($self) {
            $view->path = $self->get('flight.views.path');
            $view->extension = $self->get('flight.views.extension');
        });

        // Register framework methods
        $methods = array(
            'start','stop','route','halt','error','notFound',
            'render','redirect','etag','lastModified','json','jsonp'
        );
        foreach ($methods as $name) {
            $this->dispatcher->set($name, array($this, '_'.$name));
        }

        // Default configuration settings
        $this->set('flight.base_url', null);
        $this->set('flight.case_sensitive', false);
        $this->set('flight.handle_errors', true);
        $this->set('flight.log_errors', false);
        $this->set('flight.views.path', './views');
        $this->set('flight.views.extension', '.php');

        // Startup configuration
        $this->before('start', function() use ($self) {
            // Enable error handling
            if ($self->get('flight.handle_errors')) {
                set_error_handler(array($self, 'handleError'));
                set_exception_handler(array($self, 'handleException'));
            }

            // Set case-sensitivity
            $self->router()->case_sensitive = $self->get('flight.case_sensitive');
        });

        $initialized = true;
    }

public
function
init
(
)
{
static
$
initialized
=
false
;
$
self
=
$
this
;
if
(
$
initialized
)
{
$
this
->
vars
=
array
(
)
;
$
this
->
loader
->
reset
(
)
;
$
this
->
dispatcher
->
reset
(
)
;
}
// Register default components
$
this
->
loader
->
register
(
'request'
,
'\flight\net\Request'
)
;
$
this
->
loader
->
register
(
'response'
,
'\flight\net\Response'
)
;
$
this
->
loader
->
register
(
'router'
,
'\flight\net\Router'
)
;
$
this
->
loader
->
register
(
'view'
,
'\flight\template\View'
,
array
(
)
,
function
(
$
view
)
use
(
$
self
)
{
$
view
->
path
=
$
self
->
get
(
'flight.views.path'
)
;
$
view
->
extension
=
$
self
->
get
(
'flight.views.extension'
)
;
}
)
;
// Register framework methods
$
methods
=
array
(
'start'
,
'stop'
,
'route'
,
'halt'
,
'error'
,
'notFound'
,
'render'
,
'redirect'
,
'etag'
,
'lastModified'
,
'json'
,
'jsonp'
)
;
foreach
(
$
methods
as
$
name
)
{
$
this
->
dispatcher
->
set
(
$
name
,
array
(
$
this
,
'_'
.
$
name
)
)
;
}
// Default configuration settings
$
this
->
set
(
'flight.base_url'
,
)
;
$
this
->
set
(
'flight.case_sensitive'
,
false
)
;
$
this
->
set
(
'flight.handle_errors'
,
true
)
;
$
this
->
set
(
'flight.log_errors'
,
false
)
;
$
this
->
set
(
'flight.views.path'
,
'./views'
)
;
$
this
->
set
(
'flight.views.extension'
,
'.php'
)
;
// Startup configuration
$
this
->
before
(
'start'
,
function
(
)
use
(
$
self
)
{
// Enable error handling
if
(
$
self
->
get
(
'flight.handle_errors'
)
)
{
set_error_handler
(
array
(
$
self
,
'handleError'
)
)
;
set_exception_handler
(
array
(
$
self
,
'handleException'
)
)
;
}
// Set case-sensitivity
$
self
->
router
(
)
->
case_sensitive
=
$
self
->
get
(
'flight.case_sensitive'
)
;
}
)
;
$
initialized
=
true
;
}


public function handleError($errno, $errstr, $errfile, $errline) {
        if ($errno & error_reporting()) {
            throw new \ErrorException($errstr, $errno, 0, $errfile, $errline);
        }
    }

public function handleError ( $ errno , $ errstr , $ errfile , $ errline ) { if ( $ errno & error_reporting ( ) ) { throw new \ ErrorException ( $ errstr , $ errno , 0 , $ errfile , $ errline ) ; } }

Custom error handler. Converts errors into exceptions.

@param int $errno Error number
@param int $errstr Error string
@param int $errfile Error file name
@param int $errline Error file line number
@throws \ErrorException

Custom error handler . Converts errors into exceptions .


public function handleException($e) {
        if ($this->get('flight.log_errors')) {
            error_log($e->getMessage());
        }

        $this->error($e);
    }

public function handleException ( $ e ) { if ( $ this -> get ( 'flight.log_errors' ) ) { error_log ( $ e -> getMessage ( ) ) ; } $ this -> error ( $ e ) ; }

Custom exception handler. Logs exceptions.

@param \Exception $e Thrown exception

Custom exception handler . Logs exceptions .


public function map($name, $callback) {
        if (method_exists($this, $name)) {
            throw new \Exception('Cannot override an existing framework method.');
        }

        $this->dispatcher->set($name, $callback);
    }

Maps a callback to a framework method.

@param string $name Method name
@param callback $callback Callback function
@throws \Exception If trying to map over a framework method


public function register($name, $class, array $params = array(), $callback = null) {
        if (method_exists($this, $name)) {
            throw new \Exception('Cannot override an existing framework method.');
        }

        $this->loader->register($name, $class, $params, $callback);
    }

Registers a class to a framework method.

@param string $name Method name
@param string $class Class name
@param array $params Class initialization parameters
@param callback $callback Function to call after object instantiation
@throws \Exception If trying to map over a framework method

Registers a class to a framework method .


public function get($key = null) {
        if ($key === null) return $this->vars;

        return isset($this->vars[$key]) ? $this->vars[$key] : null;
    }

public function get ( $ key = null ) { if ( $ key === null ) return $ this -> vars ; return isset ( $ this -> vars [ $ key ] ) ? $ this -> vars [ $ key ] : null ; }

Gets a variable.

@param string $key Key
@return mixed


public function clear($key = null) {
        if (is_null($key)) {
            $this->vars = array();
        }
        else {
            unset($this->vars[$key]);
        }
    }

public function clear ( $ key = null ) { if ( is_null ( $ key ) ) { $ this -> vars = array ( ) ; } else { unset ( $ this -> vars [ $ key ] ) ; } }

Unsets a variable. If no key is passed in, clear all variables.

@param string $key Key

Unsets a variable . If no key is passed in clear all variables .


public function _start() {
        $dispatched = false;
        $self = $this;
        $request = $this->request();
        $response = $this->response();
        $router = $this->router();

        // Allow filters to run
        $this->after('start', function() use ($self) {
            $self->stop();
        });

        // Flush any existing output
        if (ob_get_length() > 0) {
            $response->write(ob_get_clean());
        }

        // Enable output buffering
        ob_start();

        // Route the request
        while ($route = $router->route($request)) {
            $params = array_values($route->params);

            // Add route info to the parameter list
            if ($route->pass) {
                $params[] = $route;
            }

            // Call route handler
            $continue = $this->dispatcher->execute(
                $route->callback,
                $params
            );

            $dispatched = true;

            if (!$continue) break;

            $router->next();

            $dispatched = false;
        }

        if (!$dispatched) {
            $this->notFound();
        }
    }

public
function
_start
(
)
{
$
dispatched
=
false
;
$
self
=
$
this
;
$
request
=
$
this
->
request
(
)
;
$
response
=
$
this
->
response
(
)
;
$
router
=
$
this
->
router
(
)
;
// Allow filters to run
$
this
->
after
(
'start'
,
function
(
)
use
(
$
self
)
{
$
self
->
stop
(
)
;
}
)
;
// Flush any existing output
if
(
ob_get_length
(
)
>
0
)
{
$
response
->
write
(
ob_get_clean
(
)
)
;
}
// Enable output buffering
ob_start
(
)
;
// Route the request
while
(
$
route
=
$
router
->
route
(
$
request
)
)
{
$
params
=
array_values
(
$
route
->
params
)
;
// Add route info to the parameter list
if
(
$
route
->
pass
)
{
$
params
[
]
=
$
route
;
}
// Call route handler
$
continue
=
$
this
->
dispatcher
->
execute
(
$
route
->
callback
,
$
params
)
;
$
dispatched
=
true
;
if
(
!
$
continue
)
break
;
$
router
->
next
(
)
;
$
dispatched
=
false
;
}
if
(
!
$
dispatched
)
{
$
this
->
notFound
(
)
;
}
}

Starts the framework.
@throws \Exception


public function _stop($code = null) {
        $response = $this->response();

        if (!$response->sent()) {
            if ($code !== null) {
                $response->status($code);
            }

            $response->write(ob_get_clean());

            $response->send();
        }
    }

public function _stop ( $ code = null ) { $ response = $ this -> response ( ) ; if ( ! $ response -> sent ( ) ) { if ( $ code !== null ) { $ response -> status ( $ code ) ; } $ response -> write ( ob_get_clean ( ) ) ; $ response -> send ( ) ; } }

Stops the framework and outputs the current response.

@param int $code HTTP status code
@throws \Exception

Stops the framework and outputs the current response .


public function _route($pattern, $callback, $pass_route = false) {
        $this->router()->map($pattern, $callback, $pass_route);
    }

public function _route ( $ pattern , $ callback , $ pass_route = false ) { $ this -> router ( ) -> map ( $ pattern , $ callback , $ pass_route ) ; }

Routes a URL to a callback function.

@param string $pattern URL pattern to match
@param callback $callback Callback function
@param boolean $pass_route Pass the matching route object to the callback


public function _halt($code = 200, $message = '') {
        $this->response()
            ->clear()
            ->status($code)
            ->write($message)
            ->send();
        exit();
    }

public function _halt ( $ code = 200 , $ message = '' ) { $ this -> response ( ) -> clear ( ) -> status ( $ code ) -> write ( $ message ) -> send ( ) ; exit ( ) ; }

Stops processing and returns a given response.

@param int $code HTTP status code
@param string $message Response message

Stops processing and returns a given response .


public function _error($e) {
        $msg = sprintf('
500 Internal Server Error
'.
            '
%s (%s)
'.
            '
%s
',
            $e->getMessage(),
            $e->getCode(),
            $e->getTraceAsString()
        );

        try {
            $this->response()
                ->clear()
                ->status(500)
                ->write($msg)
                ->send();
        }
        catch (\Throwable $t) { // PHP 7.0+
            exit($msg);
        } catch(\Exception $e) { // PHP < 7
            exit($msg);
        }
    }

public
function
_error
(
$
e
)
{
$
msg
=
sprintf
(
'
500 Internal Server Error
'
.
'
%s (%s)
'
.
'
%s
'
,
$
e
->
getMessage
(
)
,
$
e
->
getCode
(
)
,
$
e
->
getTraceAsString
(
)
)
;
try
{
$
this
->
response
(
)
->
clear
(
)
->
status
(
500
)
->
write
(
$
msg
)
->
send
(
)
;
}
catch
(
\
Throwable
$
t
)
{
// PHP 7.0+
exit
(
$
msg
)
;
}
catch
(
\
Exception
$
e
)
{
// PHP < 7
exit
(
$
msg
)
;
}
}

Sends an HTTP 500 response for any errors.

@param \Exception|\Throwable $e Thrown exception

Sends an HTTP 500 response for any errors .


public function _redirect($url, $code = 303) {
        $base = $this->get('flight.base_url');

        if ($base === null) {
            $base = $this->request()->base;
        }

        // Append base url to redirect url
        if ($base != '/' && strpos($url, '://') === false) {
            $url = $base . preg_replace('#/+#', '/', '/' . $url);
        }

        $this->response()
            ->clear()
            ->status($code)
            ->header('Location', $url)
            ->send();
    }

public
function
_redirect
(
$
url
,
$
code
=
303
)
{
$
base
=
$
this
->
get
(
'flight.base_url'
)
;
if
(
$
base
===
)
{
$
base
=
$
this
->
request
(
)
->
base
;
}
// Append base url to redirect url
if
(
$
base
!=
'/'
&&
strpos
(
$
url
,
'://'
)
===
false
)
{
$
url
=
$
base
.
preg_replace
(
'#/+#'
,
'/'
,
'/'
.
$
url
)
;
}
$
this
->
response
(
)
->
clear
(
)
->
status
(
$
code
)
->
header
(
'Location'
,
$
url
)
->
send
(
)
;
}

Redirects the current request to another URL.

@param string $url URL
@param int $code HTTP status code

Redirects the current request to another URL .


public function _json(
        $data,
        $code = 200,
        $encode = true,
        $charset = 'utf-8',
        $option = 0
    ) {
        $json = ($encode) ? json_encode($data, $option) : $data;

        $this->response()
            ->status($code)
            ->header('Content-Type', 'application/json; charset='.$charset)
            ->write($json)
            ->send();
    }

public
function
_json
(
$
data
,
$
code
=
200
,
$
encode
=
true
,
$
charset
=
'utf-8'
,
$
option
=
0
)
{
$
json
=
(
$
encode
)
json_encode
(
$
data
,
$
option
)
:
$
data
;
$
this
->
response
(
)
->
status
(
$
code
)
->
header
(
'Content-Type'
,
'application/json; charset='
.
$
charset
)
->
write
(
$
json
)
->
send
(
)
;
}

Sends a JSON response.

@param mixed $data JSON data
@param int $code HTTP status code
@param bool $encode Whether to perform JSON encoding
@param string $charset Charset
@param int $option Bitmask Json constant such as JSON_HEX_QUOT
@throws \Exception


public function _jsonp(
        $data,
        $param = 'jsonp',
        $code = 200,
        $encode = true,
        $charset = 'utf-8',
        $option = 0
    ) {
        $json = ($encode) ? json_encode($data, $option) : $data;

        $callback = $this->request()->query[$param];

        $this->response()
            ->status($code)
            ->header('Content-Type', 'application/javascript; charset='.$charset)
            ->write($callback.'('.$json.');')
            ->send();
    }

public
function
_jsonp
(
$
data
,
$
param
=
'jsonp'
,
$
code
=
200
,
$
encode
=
true
,
$
charset
=
'utf-8'
,
$
option
=
0
)
{
$
json
=
(
$
encode
)
json_encode
(
$
data
,
$
option
)
:
$
data
;
$
callback
=
$
this
->
request
(
)
->
query
[
$
param
]
;
$
this
->
response
(
)
->
status
(
$
code
)
->
header
(
'Content-Type'
,
'application/javascript; charset='
.
$
charset
)
->
write
(
$
callback
.
'('
.
$
json
.
');'
)
->
send
(
)
;
}

Sends a JSONP response.

@param mixed $data JSON data
@param string $param Query parameter that specifies the callback name.
@param int $code HTTP status code
@param bool $encode Whether to perform JSON encoding
@param string $charset Charset
@param int $option Bitmask Json constant such as JSON_HEX_QUOT
@throws \Exception


public function _etag($id, $type = 'strong') {
        $id = (($type === 'weak') ? 'W/' : '').$id;

        $this->response()->header('ETag', $id);

        if (isset($_SERVER['HTTP_IF_NONE_MATCH']) &&
            $_SERVER['HTTP_IF_NONE_MATCH'] === $id) {
            $this->halt(304);
        }
    }

public function _etag ( $ id , $ type = 'strong' ) { $ id = ( ( $ type === 'weak' ) ? 'W/' : '' ) . $ id ; $ this -> response ( ) -> header ( 'ETag' , $ id ) ; if ( isset ( $ _SERVER [ 'HTTP_IF_NONE_MATCH' ] ) && $ _SERVER [ 'HTTP_IF_NONE_MATCH' ] === $ id ) { $ this -> halt ( 304 ) ; } }

Handles ETag HTTP caching.

@param string $id ETag identifier
@param string $type ETag type


public function _lastModified($time) {
        $this->response()->header('Last-Modified', gmdate('D, d M Y H:i:s \G\M\T', $time));

        if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) &&
            strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) === $time) {
            $this->halt(304);
        }
    }

public
function
_lastModified
(
$
time
)
{
$
this
->
response
(
)
->
header
(
'Last-Modified'
,
gmdate
(
'D, d M Y H:i:s \G\M\T'
,
$
time
)
)
;
if
(
isset
(
$
_SERVER
[
'HTTP_IF_MODIFIED_SINCE'
]
)
&&
strtotime
(
$
_SERVER
[
'HTTP_IF_MODIFIED_SINCE'
]
)
===
$
time
)
{
$
this
->
halt
(
304
)
;
}
}

Handles last modified HTTP caching.

@param int $time Unix timestamp


public function register($name, $class, array $params = array(), $callback = null) {
        unset($this->instances[$name]);

        $this->classes[$name] = array($class, $params, $callback);
    }

public function register ( $ name , $ class , array $ params = array ( ) , $ callback = null ) { unset ( $ this -> instances [ $ name ] ) ; $ this -> classes [ $ name ] = array ( $ class , $ params , $ callback ) ; }

Registers a class.

@param string $name Registry name
@param string|callable $class Class name or function to instantiate class
@param array $params Class initialization parameters
@param callback $callback Function to call after object instantiation


public function load($name, $shared = true) {
        $obj = null;

        if (isset($this->classes[$name])) {
            list($class, $params, $callback) = $this->classes[$name];

            $exists = isset($this->instances[$name]);

            if ($shared) {
                $obj = ($exists) ?
                    $this->getInstance($name) :
                    $this->newInstance($class, $params);

                if (!$exists) {
                    $this->instances[$name] = $obj;
                }
            }
            else {
                $obj = $this->newInstance($class, $params);
            }

            if ($callback && (!$shared || !$exists)) {
                $ref = array(&$obj);
                call_user_func_array($callback, $ref);
            }
        }

        return $obj;
    }

public function load ( $ name , $ shared = true ) { $ obj = null ; if ( isset ( $ this -> classes [ $ name ] ) ) { list ( $ class , $ params , $ callback ) = $ this -> classes [ $ name ] ; $ exists = isset ( $ this -> instances [ $ name ] ) ; if ( $ shared ) { $ obj = ( $ exists ) ? $ this -> getInstance ( $ name ) : $ this -> newInstance ( $ class , $ params ) ; if ( ! $ exists ) { $ this -> instances [ $ name ] = $ obj ; } } else { $ obj = $ this -> newInstance ( $ class , $ params ) ; } if ( $ callback && ( ! $ shared || ! $ exists ) ) { $ ref = array ( & $ obj ) ; call_user_func_array ( $ callback , $ ref ) ; } } return $ obj ; }

Loads a registered class.

@param string $name Method name
@param bool $shared Shared instance
@return object Class instance
@throws \Exception


public function getInstance($name) {
        return isset($this->instances[$name]) ? $this->instances[$name] : null;
    }

public function getInstance ( $ name ) { return isset ( $ this -> instances [ $ name ] ) ? $ this -> instances [ $ name ] : null ; }

Gets a single instance of a class.

@param string $name Instance name
@return object Class instance


public function newInstance($class, array $params = array()) {
        if (is_callable($class)) {
            return call_user_func_array($class, $params);
        }

        switch (count($params)) {
            case 0:
                return new $class();
            case 1:
                return new $class($params[0]);
            case 2:
                return new $class($params[0], $params[1]);
            case 3:
                return new $class($params[0], $params[1], $params[2]);
            case 4:
                return new $class($params[0], $params[1], $params[2], $params[3]);
            case 5:
                return new $class($params[0], $params[1], $params[2], $params[3], $params[4]);
            default:
                try {
                    $refClass = new \ReflectionClass($class);
                    return $refClass->newInstanceArgs($params);
                } catch (\ReflectionException $e) {
                    throw new \Exception("Cannot instantiate {$class}", 0, $e);
                }
        }
    }

public
function
newInstance
(
$
class
,
array
$
params
=
array
(
)
)
{
if
(
is_callable
(
$
class
)
)
{
return
call_user_func_array
(
$
class
,
$
params
)
;
}
switch
(
count
(
$
params
)
)
{
case
0
:
return
new
$
class
(
)
;
case
1
:
return
new
$
class
(
$
params
[
0
]
)
;
case
2
:
return
new
$
class
(
$
params
[
0
]
,
$
params
[
1
]
)
;
case
3
:
return
new
$
class
(
$
params
[
0
]
,
$
params
[
1
]
,
$
params
[
2
]
)
;
case
4
:
return
new
$
class
(
$
params
[
0
]
,
$
params
[
1
]
,
$
params
[
2
]
,
$
params
[
3
]
)
;
case
5
:
return
new
$
class
(
$
params
[
0
]
,
$
params
[
1
]
,
$
params
[
2
]
,
$
params
[
3
]
,
$
params
[
4
]
)
;
default
:
try
{
$
refClass
=
new
\
ReflectionClass
(
$
class
)
;
return
$
refClass
->
newInstanceArgs
(
$
params
)
;
}
catch
(
\
ReflectionException
$
e
)
{
throw
new
\
Exception
(
"Cannot instantiate {$class}"
,
0
,
$
e
)
;
}
}
}

Gets a new instance of a class.

@param string|callable $class Class name or callback function to instantiate class
@param array $params Class initialization parameters
@return object Class instance
@throws \Exception


public static function loadClass($class) {
        $class_file = str_replace(array('\\', '_'), '/', $class).'.php';

        foreach (self::$dirs as $dir) {
            $file = $dir.'/'.$class_file;
            if (file_exists($file)) {
                require $file;
                return;
            }
        }
    }

public static function loadClass ( $ class ) { $ class_file = str_replace ( array ( '\\' , '_' ) , '/' , $ class ) . '.php' ; foreach ( self :: $ dirs as $ dir ) { $ file = $ dir . '/' . $ class_file ; if ( file_exists ( $ file ) ) { require $ file ; return ; } } }

Autoloads classes.

@param string $class Class name


public static function addDirectory($dir) {
        if (is_array($dir) || is_object($dir)) {
            foreach ($dir as $value) {
                self::addDirectory($value);
            }
        }
        else if (is_string($dir)) {
            if (!in_array($dir, self::$dirs)) self::$dirs[] = $dir;
        }
    }

public static function addDirectory ( $ dir ) { if ( is_array ( $ dir ) || is_object ( $ dir ) ) { foreach ( $ dir as $ value ) { self :: addDirectory ( $ value ) ; } } else if ( is_string ( $ dir ) ) { if ( ! in_array ( $ dir , self :: $ dirs ) ) self :: $ dirs [ ] = $ dir ; } }

Adds a directory for autoloading classes.

@param mixed $dir Directory path

Adds a directory for autoloading classes .


public function fetch($file, $data = null) {
        ob_start();

        $this->render($file, $data);
        $output = ob_get_clean();

        return $output;
    }

public function fetch ( $ file , $ data = null ) { ob_start ( ) ; $ this -> render ( $ file , $ data ) ; $ output = ob_get_clean ( ) ; return $ output ; }

Gets the output of a template.

@param string $file Template file
@param array $data Template data
@return string Output of template


public function getTemplate($file) {
        $ext = $this->extension;

        if (!empty($ext) && (substr($file, -1 * strlen($ext)) != $ext)) {
            $file .= $ext;
        }

        if ((substr($file, 0, 1) == '/')) {
            return $file;
        }

        return $this->path.'/'.$file;
    }

public function getTemplate ( $ file ) { $ ext = $ this -> extension ; if ( ! empty ( $ ext ) && ( substr ( $ file , - 1 * strlen ( $ ext ) ) != $ ext ) ) { $ file .= $ ext ; } if ( ( substr ( $ file , 0 , 1 ) == '/' ) ) { return $ file ; } return $ this -> path . '/' . $ file ; }

Gets the full path to a template file.

@param string $file Template file
@return string Template file location


public function isCyclic(Graph $graph)
    {
        // prepare stack
        $recursionStack = [];
        foreach ($graph->all() as $node) {
            $recursionStack[$node->getKey()] = false;
        }

        // start analysis
        $isCyclic = false;
        foreach ($graph->getEdges() as $edge) {
            if ($r = $this->detectCycle($edge->getFrom(), $recursionStack)) {
                $edge->cyclic = true;
                $isCyclic = true;
            }

            $recursionStack[$node->getKey()] = false;
        }

        $graph->resetVisits();

        return $isCyclic;
    }

public
function
isCyclic
(
Graph
$
graph
)
{
// prepare stack
$
recursionStack
=
[
]
;
foreach
(
$
graph
->
all
(
)
as
$
node
)
{
$
recursionStack
[
$
node
->
getKey
(
)
]
=
false
;
}
// start analysis
$
isCyclic
=
false
;
foreach
(
$
graph
->
getEdges
(
)
as
$
edge
)
{
if
(
$
r
=
$
this
->
detectCycle
(
$
edge
->
getFrom
(
)
,
$
recursionStack
)
)
{
$
edge
->
cyclic
=
true
;
$
isCyclic
=
true
;
}
$
recursionStack
[
$
node
->
getKey
(
)
]
=
false
;
}
$
graph
->
resetVisits
(
)
;
return
$
isCyclic
;
}

Check if graph contains cycle

Each node in cycle is flagged with the "cyclic" attribute

@param Graph $graph
@return bool


public function getAverageHeightOfGraph()
    {
        $ns = [];
        foreach ($this->graph->getRootNodes() as $node) {
            array_push($ns, $this->getLongestBranch($node));
        }
        return round(array_sum($ns) / max(1, sizeof($ns)), 2);
    }

public function getAverageHeightOfGraph ( ) { $ ns = [ ] ; foreach ( $ this -> graph -> getRootNodes ( ) as $ node ) { array_push ( $ ns , $ this -> getLongestBranch ( $ node ) ) ; } return round ( array_sum ( $ ns ) / max ( 1 , sizeof ( $ ns ) ) , 2 ) ; }

Get average height of graph

@return float


private function collapseArray(array $arr)
    {
        $iterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($arr));
        $result = [];
        foreach ($iterator as $leafValue) {
            $keys = [];
            foreach (range(0, $iterator->getDepth()) as $depth) {
                $keys[] = $iterator->getSubIterator($depth)->key();
            }
            $result[join('-', $keys)] = $leafValue;
        }

        return $result;
    }

private function collapseArray ( array $ arr ) { $ iterator = new RecursiveIteratorIterator ( new RecursiveArrayIterator ( $ arr ) ) ; $ result = [ ] ; foreach ( $ iterator as $ leafValue ) { $ keys = [ ] ; foreach ( range ( 0 , $ iterator -> getDepth ( ) ) as $ depth ) { $ keys [ ] = $ iterator -> getSubIterator ( $ depth ) -> key ( ) ; } $ result [ join ( '-' , $ keys ) ] = $ leafValue ; } return $ result ; }

Collapses array into a one-dimensional one by imploding nested keys with '-'

@param array $arr

@return array

Collapses array into a one - dimensional one by imploding nested keys with -


public function fetch(array $paths)
    {
        $files = array();
        foreach ($paths as $path) {
            if (is_dir($path)) {
                $path = rtrim($path, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
                $directory = new RecursiveDirectoryIterator($path, $this->flags);
                $iterator = new RecursiveIteratorIterator($directory);

                $filterRegex = sprintf(
                    '`^%s%s%s$`',
                    preg_quote($path, '`'),
                    !empty($this->excludedDirs) ? '((?!' . implode('|', array_map('preg_quote', $this->excludedDirs)) . ').)+' : '.+',
                    '\.(' . implode('|', $this->extensions) . ')'
                );

                $filteredIterator = new RegexIterator(
                    $iterator,
                    $filterRegex,
                    \RecursiveRegexIterator::GET_MATCH
                );

                foreach ($filteredIterator as $file) {
                    $files[] = $file[0];
                }
            } elseif (is_file($path)) {
                $files[] = $path;
            }
        }
        return $files;
    }

public function fetch ( array $ paths ) { $ files = array ( ) ; foreach ( $ paths as $ path ) { if ( is_dir ( $ path ) ) { $ path = rtrim ( $ path , DIRECTORY_SEPARATOR ) . DIRECTORY_SEPARATOR ; $ directory = new RecursiveDirectoryIterator ( $ path , $ this -> flags ) ; $ iterator = new RecursiveIteratorIterator ( $ directory ) ; $ filterRegex = sprintf ( '`^%s%s%s$`' , preg_quote ( $ path , '`' ) , ! empty ( $ this -> excludedDirs ) ? '((?!' . implode ( '|' , array_map ( 'preg_quote' , $ this -> excludedDirs ) ) . ').)+' : '.+' , '\.(' . implode ( '|' , $ this -> extensions ) . ')' ) ; $ filteredIterator = new RegexIterator ( $ iterator , $ filterRegex , \ RecursiveRegexIterator :: GET_MATCH ) ; foreach ( $ filteredIterator as $ file ) { $ files [ ] = $ file [ 0 ] ; } } elseif ( is_file ( $ path ) ) { $ files [ ] = $ path ; } } return $ files ; }

Find files in path

@param array $paths
@return array
@internal param string $path


private function traverse(TreeNode $node)
    {
        if ($node->visited) {
            return 0;
        }
        $node->visited = true;

        foreach ($node->getAdjacents() as $adjacent) {
            $this->traverse($adjacent);
        }

        return 1;
    }

private function traverse ( TreeNode $ node ) { if ( $ node -> visited ) { return 0 ; } $ node -> visited = true ; foreach ( $ node -> getAdjacents ( ) as $ adjacent ) { $ this -> traverse ( $ adjacent ) ; } return 1 ; }

Traverse node, and return 1 if node has not been visited yet

@param TreeNode $node
@return int

Traverse node and return 1 if node has not been visited yet


public function getRootNodes()
    {
        $roots = [];
        foreach ($this->all() as $node) {

            $isRoot = true;

            foreach ($node->getEdges() as $edge) {
                if ($edge->getTo() == $node) {
                    $isRoot = false;
                }
            }

            if ($isRoot) {
                array_push($roots, $node);
            }
        }

        return $roots;
    }

public function getRootNodes ( ) { $ roots = [ ] ; foreach ( $ this -> all ( ) as $ node ) { $ isRoot = true ; foreach ( $ node -> getEdges ( ) as $ edge ) { if ( $ edge -> getTo ( ) == $ node ) { $ isRoot = false ; } } if ( $ isRoot ) { array_push ( $ roots , $ node ) ; } } return $ roots ; }

Get the list of all root nodes

we can have array of roots : graph can be a "forest"

@return array


protected function getComposerLockInstalled($rootPackageRequirements)
    {
        $rawInstalled = [[]];

        // Find composer.lock file
        $finder = new Finder(['lock'], $this->config->get('exclude'));
        $files = $finder->fetch($this->config->get('files'));

        // List all composer.lock found in the project.
        foreach ($files as $filename) {
            if (false === \strpos($filename, 'composer.lock')) {
                continue;
            }
            $composerLockJson = (object)\json_decode(\file_get_contents($filename));

            if (!isset($composerLockJson->packages)) {
                continue;
            }

            $installed = [];
            foreach ($composerLockJson->packages as $package) {
                if (!\in_array($package->name, $rootPackageRequirements, true)) {
                    continue;
                }

                $installed[$package->name] = \preg_replace('#[^.\d]#', '', $package->version);
            }

            $rawInstalled[] = $installed;
        }

        return \call_user_func_array('array_merge', $rawInstalled);
    }

Returns the installed packages from the composer.lock file.
@param array $rootPackageRequirements List of requirements to match installed packages only with requirements.
@return array

Returns the installed packages from the composer . lock file .


public function advance()
    {
        $this->current++;

        if ($this->hasAnsi()) {
            $percent = round($this->current / $this->max * 100);
            $this->output->write("\x0D");
            $this->output->write("\x1B[2K");
            $this->output->write(sprintf('... %s%% ...', $percent));
        } else {
            $this->output->write('.');
        }
    }

public
function
advance
(
)
{
$
this
->
current
++
;
if
(
$
this
->
hasAnsi
(
)
)
{
$
percent
=
round
(
$
this
->
current
/
$
this
->
max
*
100
)
;
$
this
->
output
->
write
(
"\x0D"
)
;
$
this
->
output
->
write
(
"\x1B[2K"
)
;
$
this
->
output
->
write
(
sprintf
(
'... %s%% ...'
,
$
percent
)
)
;
}
else
{
$
this
->
output
->
write
(
'.'
)
;
}
}


protected function hasAnsi()
    {
        if (DIRECTORY_SEPARATOR === '\\') {
            return
                0 >= version_compare('10.0.10586',
                    PHP_WINDOWS_VERSION_MAJOR . '.' . PHP_WINDOWS_VERSION_MINOR . '.' . PHP_WINDOWS_VERSION_BUILD)
                || false !== getenv('ANSICON')
                || 'ON' === getenv('ConEmuANSI')
                || 'xterm' === getenv('TERM');
        }

        return function_exists('posix_isatty') && @posix_isatty($this->stream);
    }

protected function hasAnsi ( ) { if ( DIRECTORY_SEPARATOR === '\\' ) { return 0 >= version_compare ( '10.0.10586' , PHP_WINDOWS_VERSION_MAJOR . '.' . PHP_WINDOWS_VERSION_MINOR . '.' . PHP_WINDOWS_VERSION_BUILD ) || false !== getenv ( 'ANSICON' ) || 'ON' === getenv ( 'ConEmuANSI' ) || 'xterm' === getenv ( 'TERM' ) ; } return function_exists ( 'posix_isatty' ) && @ posix_isatty ( $ this -> stream ) ; }


public function process_no_parameters( $stackPtr, $group_name, $matched_content ) {

		$target_param = $this->target_functions[ $matched_content ];

		if ( 1 !== $target_param ) {
			// Only process the no param case as fixable if the text domain is expected to be the first parameter.
			$this->phpcsFile->addWarning( 'Missing $domain arg and preceding argument(s)', $stackPtr, 'MissingArgs' );
			return;
		}

		$opener = $this->phpcsFile->findNext( Tokens::$emptyTokens, ( $stackPtr + 1 ), null, true );
		if ( \T_OPEN_PARENTHESIS !== $this->tokens[ $opener ]['code']
			|| isset( $this->tokens[ $opener ]['parenthesis_closer'] ) === false
		) {
			// Parse error or live coding.
			return;
		}

		$fix = $this->phpcsFile->addFixableError( 'Missing $domain arg', $stackPtr, 'MissingArgDomain' );
		if ( true === $fix ) {
			$closer      = $this->tokens[ $opener ]['parenthesis_closer'];
			$replacement = " '{$this->new_text_domain}' ";

			if ( $this->tokens[ $opener ]['line'] !== $this->tokens[ $closer ]['line'] ) {
				$replacement = trim( $replacement );
				$addBefore   = ( $closer - 1 );
				if ( \T_WHITESPACE === $this->tokens[ ( $closer - 1 ) ]['code']
					&& $this->tokens[ $closer - 1 ]['line'] === $this->tokens[ $closer ]['line']
				) {
					if ( isset( $this->tokens[ ( $closer - 1 ) ]['orig_content'] ) ) {
						$replacement = $this->tokens[ ( $closer - 1 ) ]['orig_content']
							. "\t"
							. $replacement;
					} else {
						$replacement = $this->tokens[ ( $closer - 1 ) ]['content']
							. str_repeat( ' ', $this->tab_width )
							. $replacement;
					}

					--$addBefore;
				} else {
					// We don't know whether the code uses tabs or spaces, so presume WPCS, i.e. tabs.
					$replacement = "\t" . $replacement;
				}

				$replacement = $this->phpcsFile->eolChar . $replacement;

				$this->phpcsFile->fixer->addContentBefore( $addBefore, $replacement );

			} elseif ( \T_WHITESPACE === $this->tokens[ ( $closer - 1 ) ]['code'] ) {
				$this->phpcsFile->fixer->replaceToken( ( $closer - 1 ), $replacement );
			} else {
				$this->phpcsFile->fixer->addContentBefore( $closer, $replacement );
			}
		}
	}

Process the function if no parameters were found.

@since 1.2.0

@param int    $stackPtr        The position of the current token in the stack.
@param array  $group_name      The name of the group which was matched.
@param string $matched_content The token content (function name) which was matched.

@return void

Process the function if no parameters were found .


public function process( File $phpcsFile, $stackPtr ) {
		$this->init( $phpcsFile );
		return $this->process_token( $stackPtr );
	}

public function process ( File $ phpcsFile , $ stackPtr ) { $ this -> init ( $ phpcsFile ) ; return $ this -> process_token ( $ stackPtr ) ; }

Set sniff properties and hand off to child class for processing of the token.

@since 0.11.0

@param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
@param int                         $stackPtr  The position of the current token
in the stack passed in $tokens.

@return int|void Integer stack pointer to skip forward or void to continue
normal file processing.

Set sniff properties and hand off to child class for processing of the token .


protected function init( File $phpcsFile ) {
		$this->phpcsFile = $phpcsFile;
		$this->tokens    = $phpcsFile->getTokens();
	}

protected function init ( File $ phpcsFile ) { $ this -> phpcsFile = $ phpcsFile ; $ this -> tokens = $ phpcsFile -> getTokens ( ) ; }

Initialize the class for the current process.

This method must be called by child classes before using many of the methods
below.

@since 0.4.0

@param \PHP_CodeSniffer\Files\File $phpcsFile The file currently being processed.

Initialize the class for the current process .


protected function addFixableMessage( $message, $stackPtr, $is_error = true, $code = 'Found', $data = array(), $severity = 0 ) {
		return $this->throwMessage( $message, $stackPtr, $is_error, $code, $data, $severity, true );
	}

protected function addFixableMessage ( $ message , $ stackPtr , $ is_error = true , $ code = 'Found' , $ data = array ( ) , $ severity = 0 ) { return $ this -> throwMessage ( $ message , $ stackPtr , $ is_error , $ code , $ data , $ severity , true ) ; }

Add a fixable PHPCS message to the output stack as either a warning or an error.

@since 0.11.0

@param string $message   The message.
@param int    $stackPtr  The position of the token the message relates to.
@param bool   $is_error  Optional. Whether to report the message as an 'error' or 'warning'.
Defaults to true (error).
@param string $code      Optional error code for the message. Defaults to 'Found'.
@param array  $data      Optional input for the data replacements.
@param int    $severity  Optional. Severity level. Defaults to 0 which will translate to
the PHPCS default severity level.
@return bool

Add a fixable PHPCS message to the output stack as either a warning or an error .


public static function merge_custom_array( $custom, $base = array(), $flip = true ) {
		if ( true === $flip ) {
			$base = array_filter( $base );
		}

		if ( empty( $custom ) || ! \is_array( $custom ) ) {
			return $base;
		}

		if ( true === $flip ) {
			$custom = array_fill_keys( $custom, false );
		}

		if ( empty( $base ) ) {
			return $custom;
		}

		return array_merge( $base, $custom );
	}

public static function merge_custom_array ( $ custom , $ base = array ( ) , $ flip = true ) { if ( true === $ flip ) { $ base = array_filter ( $ base ) ; } if ( empty ( $ custom ) || ! \ is_array ( $ custom ) ) { return $ base ; } if ( true === $ flip ) { $ custom = array_fill_keys ( $ custom , false ) ; } if ( empty ( $ base ) ) { return $ custom ; } return array_merge ( $ base , $ custom ) ; }

Merge a pre-set array with a ruleset provided array.

- By default flips custom lists to allow for using `isset()` instead
of `in_array()`.
- When `$flip` is true:
* Presumes the base array is in a `'value' => true` format.
* Any custom items will be given the value `false` to be able to
distinguish them from pre-set (base array) values.
* Will filter previously added custom items out from the base array
before merging/returning to allow for resetting to the base array.

{@internal Function is static as it doesn't use any of the properties or others
methods anyway and this way the `WordPress.NamingConventions.ValidVariableName` sniff
which extends an upstream sniff can also use it.}}

@since 0.11.0
@since 2.0.0  No longer supports custom array properties which were incorrectly
passed as a string.

@param array $custom Custom list as provided via a ruleset.
@param array $base   Optional. Base list. Defaults to an empty array.
Expects `value => true` format when `$flip` is true.
@param bool  $flip   Optional. Whether or not to flip the custom list.
Defaults to true.
@return array

Merge a pre - set array with a ruleset provided array .


protected function get_last_ptr_on_line( $stackPtr ) {

		$tokens      = $this->tokens;
		$currentLine = $tokens[ $stackPtr ]['line'];
		$nextPtr     = ( $stackPtr + 1 );

		while ( isset( $tokens[ $nextPtr ] ) && $tokens[ $nextPtr ]['line'] === $currentLine ) {
			$nextPtr++;
			// Do nothing, we just want the last token of the line.
		}

		// We've made it to the next line, back up one to the last in the previous line.
		// We do this for micro-optimization of the above loop.
		$lastPtr = ( $nextPtr - 1 );

		return $lastPtr;
	}

Get the last pointer in a line.

@since 0.4.0

@param integer $stackPtr The position of the current token in the stack passed
in $tokens.

@return integer Position of the last pointer on that line.


protected function is_assignment( $stackPtr ) {

		static $valid = array(
			\T_VARIABLE             => true,
			\T_CLOSE_SQUARE_BRACKET => true,
		);

		// Must be a variable, constant or closing square bracket (see below).
		if ( ! isset( $valid[ $this->tokens[ $stackPtr ]['code'] ] ) ) {
			return false;
		}

		$next_non_empty = $this->phpcsFile->findNext(
			Tokens::$emptyTokens,
			( $stackPtr + 1 ),
			null,
			true,
			null,
			true
		);

		// No token found.
		if ( false === $next_non_empty ) {
			return false;
		}

		// If the next token is an assignment, that's all we need to know.
		if ( isset( Tokens::$assignmentTokens[ $this->tokens[ $next_non_empty ]['code'] ] ) ) {
			return true;
		}

		// Check if this is an array assignment, e.g., `$var['key'] = 'val';` .
		if ( \T_OPEN_SQUARE_BRACKET === $this->tokens[ $next_non_empty ]['code']
			&& isset( $this->tokens[ $next_non_empty ]['bracket_closer'] )
		) {
			return $this->is_assignment( $this->tokens[ $next_non_empty ]['bracket_closer'] );
		}

		return false;
	}

Check if this variable is being assigned a value.

E.g., $var = 'foo';

Also handles array assignments to arbitrary depth:

$array['key'][ $foo ][ something() ] = $bar;

@since 0.5.0

@param int $stackPtr The index of the token in the stack. This must point to
either a T_VARIABLE or T_CLOSE_SQUARE_BRACKET token.

@return bool Whether the token is a variable being assigned a value.

Check if this variable is being assigned a value .


protected function is_token_namespaced( $stackPtr ) {
		$prev = $this->phpcsFile->findPrevious( Tokens::$emptyTokens, ( $stackPtr - 1 ), null, true, null, true );

		if ( false === $prev ) {
			return false;
		}

		if ( \T_NS_SEPARATOR !== $this->tokens[ $prev ]['code'] ) {
			return false;
		}

		$before_prev = $this->phpcsFile->findPrevious( Tokens::$emptyTokens, ( $prev - 1 ), null, true, null, true );
		if ( false === $before_prev ) {
			return false;
		}

		if ( \T_STRING !== $this->tokens[ $before_prev ]['code']
			&& \T_NAMESPACE !== $this->tokens[ $before_prev ]['code']
		) {
			return false;
		}

		return true;
	}

protected function is_token_namespaced ( $ stackPtr ) { $ prev = $ this -> phpcsFile -> findPrevious ( Tokens :: $ emptyTokens , ( $ stackPtr - 1 ) , null , true , null , true ) ; if ( false === $ prev ) { return false ; } if ( \ T_NS_SEPARATOR !== $ this -> tokens [ $ prev ] [ 'code' ] ) { return false ; } $ before_prev = $ this -> phpcsFile -> findPrevious ( Tokens :: $ emptyTokens , ( $ prev - 1 ) , null , true , null , true ) ; if ( false === $ before_prev ) { return false ; } if ( \ T_STRING !== $ this -> tokens [ $ before_prev ] [ 'code' ] && \ T_NAMESPACE !== $ this -> tokens [ $ before_prev ] [ 'code' ] ) { return false ; } return true ; }

Check if a particular token is prefixed with a namespace.

@internal This will give a false positive if the file is not namespaced and the token is prefixed
with `namespace\`.

@since 2.1.0

@param int $stackPtr The index of the token in the stack.

@return bool

Check if a particular token is prefixed with a namespace .


protected function is_only_sanitized( $stackPtr ) {

		// If it isn't being sanitized at all.
		if ( ! $this->is_sanitized( $stackPtr ) ) {
			return false;
		}

		// If this isn't set, we know the value must have only been casted, because
		// is_sanitized() would have returned false otherwise.
		if ( ! isset( $this->tokens[ $stackPtr ]['nested_parenthesis'] ) ) {
			return true;
		}

		// At this point we're expecting the value to have not been casted. If it
		// was, it wasn't *only* casted, because it's also in a function.
		if ( $this->is_safe_casted( $stackPtr ) ) {
			return false;
		}

		// The only parentheses should belong to the sanitizing function. If there's
		// more than one set, this isn't *only* sanitization.
		return ( \count( $this->tokens[ $stackPtr ]['nested_parenthesis'] ) === 1 );
	}

Check if something is only being sanitized.

@since 0.5.0

@param int $stackPtr The index of the token in the stack.

@return bool Whether the token is only within a sanitization.

Check if something is only being sanitized .


protected function is_safe_casted( $stackPtr ) {

		// Get the last non-empty token.
		$prev = $this->phpcsFile->findPrevious(
			Tokens::$emptyTokens,
			( $stackPtr - 1 ),
			null,
			true
		);

		if ( false === $prev ) {
			return false;
		}

		// Check if it is a safe cast.
		return isset( $this->safe_casts[ $this->tokens[ $prev ]['code'] ] );
	}

protected
function
is_safe_casted
(
$
stackPtr
)
{
// Get the last non-empty token.
$
prev
=
$
this
->
phpcsFile
->
findPrevious
(
Tokens
::
$
emptyTokens
,
(
$
stackPtr
1
)
,
,
true
)
;
if
(
false
===
$
prev
)
{
return
false
;
}
// Check if it is a safe cast.
return
isset
(
$
this
->
safe_casts
[
$
this
->
tokens
[
$
prev
]
[
'code'
]
]
)
;
}

Check if something is being casted to a safe value.

@since 0.5.0

@param int $stackPtr The index of the token in the stack.

@return bool Whether the token being casted.

Check if something is being casted to a safe value .


protected function get_array_access_keys( $stackPtr, $all = true ) {

		$keys = array();

		if ( \T_VARIABLE !== $this->tokens[ $stackPtr ]['code'] ) {
			return $keys;
		}

		$current = $stackPtr;

		do {
			// Find the next non-empty token.
			$open_bracket = $this->phpcsFile->findNext(
				Tokens::$emptyTokens,
				( $current + 1 ),
				null,
				true
			);

			// If it isn't a bracket, this isn't an array-access.
			if ( false === $open_bracket
				|| \T_OPEN_SQUARE_BRACKET !== $this->tokens[ $open_bracket ]['code']
				|| ! isset( $this->tokens[ $open_bracket ]['bracket_closer'] )
			) {
				break;
			}

			$key = $this->phpcsFile->getTokensAsString(
				( $open_bracket + 1 ),
				( $this->tokens[ $open_bracket ]['bracket_closer'] - $open_bracket - 1 )
			);

			$keys[]  = trim( $key );
			$current = $this->tokens[ $open_bracket ]['bracket_closer'];
		} while ( isset( $this->tokens[ $current ] ) && true === $all );

		return $keys;
	}

Get the index keys of an array variable.

E.g., "bar" and "baz" in $foo['bar']['baz'].

@since 2.1.0

@param int  $stackPtr The index of the variable token in the stack.
@param bool $all      Whether to get all keys or only the first.
Defaults to `true`(= all).

@return array An array of index keys whose value is being accessed.
or an empty array if this is not array access.

Get the index keys of an array variable .


protected function get_array_access_key( $stackPtr ) {

		$keys = $this->get_array_access_keys( $stackPtr, false );

		if ( isset( $keys[0] ) ) {
			return $keys[0];
		}

		return false;
	}

protected function get_array_access_key ( $ stackPtr ) { $ keys = $ this -> get_array_access_keys ( $ stackPtr , false ) ; if ( isset ( $ keys [ 0 ] ) ) { return $ keys [ 0 ] ; } return false ; }

Get the index key of an array variable.

E.g., "bar" in $foo['bar'].

@since 0.5.0
@since 2.1.0 Now uses get_array_access_keys() under the hood.

@param int $stackPtr The index of the token in the stack.

@return string|false The array index key whose value is being accessed.

Get the index key of an array variable .


protected function is_comparison( $stackPtr, $include_coalesce = true ) {

		$comparisonTokens = Tokens::$comparisonTokens;
		if ( false === $include_coalesce ) {
			unset( $comparisonTokens[ \T_COALESCE ] );
		}

		// We first check if this is a switch statement (switch ( $var )).
		if ( isset( $this->tokens[ $stackPtr ]['nested_parenthesis'] ) ) {
			$nested_parenthesis = $this->tokens[ $stackPtr ]['nested_parenthesis'];
			$close_parenthesis  = end( $nested_parenthesis );

			if (
				isset( $this->tokens[ $close_parenthesis ]['parenthesis_owner'] )
				&& \T_SWITCH === $this->tokens[ $this->tokens[ $close_parenthesis ]['parenthesis_owner'] ]['code']
			) {
				return true;
			}
		}

		// Find the previous non-empty token. We check before the var first because
		// yoda conditions are usually expected.
		$previous_token = $this->phpcsFile->findPrevious(
			Tokens::$emptyTokens,
			( $stackPtr - 1 ),
			null,
			true
		);

		if ( isset( $comparisonTokens[ $this->tokens[ $previous_token ]['code'] ] ) ) {
			return true;
		}

		// Maybe the comparison operator is after this.
		$next_token = $this->phpcsFile->findNext(
			Tokens::$emptyTokens,
			( $stackPtr + 1 ),
			null,
			true
		);

		// This might be an opening square bracket in the case of arrays ($var['a']).
		while ( false !== $next_token && \T_OPEN_SQUARE_BRACKET === $this->tokens[ $next_token ]['code'] ) {

			$next_token = $this->phpcsFile->findNext(
				Tokens::$emptyTokens,
				( $this->tokens[ $next_token ]['bracket_closer'] + 1 ),
				null,
				true
			);
		}

		if ( false !== $next_token && isset( $comparisonTokens[ $this->tokens[ $next_token ]['code'] ] ) ) {
			return true;
		}

		return false;
	}

Check whether a variable is being compared to another value.

E.g., $var === 'foo', 1 <= $var, etc.

Also recognizes `switch ( $var )`.

@since 0.5.0
@since 2.1.0 Added the $include_coalesce parameter.

@param int  $stackPtr         The index of this token in the stack.
@param bool $include_coalesce Optional. Whether or not to regard the null
coalesce operator - ?? - as a comparison operator.
Defaults to true.
Null coalesce is a special comparison operator in this
sense as it doesn't compare a variable to whatever is
on the other side of the comparison operator.

@return bool Whether this is a comparison.

Check whether a variable is being compared to another value .


protected function is_in_array_comparison( $stackPtr ) {
		$function_ptr = $this->is_in_function_call( $stackPtr, $this->arrayCompareFunctions, true, true );
		if ( false === $function_ptr ) {
			return false;
		}

		$function_name = $this->tokens[ $function_ptr ]['content'];
		if ( true === $this->arrayCompareFunctions[ $function_name ] ) {
			return true;
		}

		if ( $this->get_function_call_parameter_count( $function_ptr ) >= $this->arrayCompareFunctions[ $function_name ] ) {
			return true;
		}

		return false;
	}

protected function is_in_array_comparison ( $ stackPtr ) { $ function_ptr = $ this -> is_in_function_call ( $ stackPtr , $ this -> arrayCompareFunctions , true , true ) ; if ( false === $ function_ptr ) { return false ; } $ function_name = $ this -> tokens [ $ function_ptr ] [ 'content' ] ; if ( true === $ this -> arrayCompareFunctions [ $ function_name ] ) { return true ; } if ( $ this -> get_function_call_parameter_count ( $ function_ptr ) >= $ this -> arrayCompareFunctions [ $ function_name ] ) { return true ; } return false ; }

Check if a token is inside of an array-value comparison function.

@since 2.1.0

@param int $stackPtr The index of the token in the stack.

@return bool Whether the token is (part of) a parameter to an
array-value comparison function.

Check if a token is inside of an array - value comparison function .


protected function get_use_type( $stackPtr ) {

		// USE keywords inside closures.
		$next = $this->phpcsFile->findNext( \T_WHITESPACE, ( $stackPtr + 1 ), null, true );

		if ( \T_OPEN_PARENTHESIS === $this->tokens[ $next ]['code'] ) {
			return 'closure';
		}

		// USE keywords for traits.
		$valid_scopes = array(
			'T_CLASS'      => true,
			'T_ANON_CLASS' => true,
			'T_TRAIT'      => true,
		);
		if ( false !== $this->valid_direct_scope( $stackPtr, $valid_scopes ) ) {
			return 'trait';
		}

		// USE keywords for classes to import to a namespace.
		return 'class';
	}

Check what type of 'use' statement a token is part of.

The T_USE token has multiple different uses:

1. In a closure: function () use ( $var ) {}
2. In a class, to import a trait: use Trait_Name
3. In a namespace, to import a class: use Some\Class;

This function will check the token and return 'closure', 'trait', or 'class',
based on which of these uses the use is being used for.

@since 0.7.0

@param int $stackPtr The position of the token to check.

@return string The type of use.

Check what type of use statement a token is part of .


protected function get_interpolated_variables( $string ) {
		$variables = array();
		if ( preg_match_all( '/(?P<backslashes>\\\\*)\$(?P<symbol>\w+)/', $string, $match_sets, \PREG_SET_ORDER ) ) {
			foreach ( $match_sets as $matches ) {
				if ( ! isset( $matches['backslashes'] ) || ( \strlen( $matches['backslashes'] ) % 2 ) === 0 ) {
					$variables[] = $matches['symbol'];
				}
			}
		}
		return $variables;
	}

Get the interpolated variable names from a string.

Check if '$' is followed by a valid variable name, and that it is not preceded by an escape sequence.

@since 0.9.0

@param string $string The contents of a T_DOUBLE_QUOTED_STRING or T_HEREDOC token.

@return array Variable names (without '$' sigil).

Get the interpolated variable names from a string .


public function does_function_call_have_parameters( $stackPtr ) {

		// Check for the existence of the token.
		if ( false === isset( $this->tokens[ $stackPtr ] ) ) {
			return false;
		}

		// Is this one of the tokens this function handles ?
		if ( false === \in_array( $this->tokens[ $stackPtr ]['code'], array( \T_STRING, \T_ARRAY, \T_OPEN_SHORT_ARRAY ), true ) ) {
			return false;
		}

		$next_non_empty = $this->phpcsFile->findNext( Tokens::$emptyTokens, ( $stackPtr + 1 ), null, true, null, true );

		// Deal with short array syntax.
		if ( 'T_OPEN_SHORT_ARRAY' === $this->tokens[ $stackPtr ]['type'] ) {
			if ( false === isset( $this->tokens[ $stackPtr ]['bracket_closer'] ) ) {
				return false;
			}

			if ( $next_non_empty === $this->tokens[ $stackPtr ]['bracket_closer'] ) {
				// No parameters.
				return false;
			} else {
				return true;
			}
		}

		// Deal with function calls & long arrays.
		// Next non-empty token should be the open parenthesis.
		if ( false === $next_non_empty && \T_OPEN_PARENTHESIS !== $this->tokens[ $next_non_empty ]['code'] ) {
			return false;
		}

		if ( false === isset( $this->tokens[ $next_non_empty ]['parenthesis_closer'] ) ) {
			return false;
		}

		$close_parenthesis   = $this->tokens[ $next_non_empty ]['parenthesis_closer'];
		$next_next_non_empty = $this->phpcsFile->findNext( Tokens::$emptyTokens, ( $next_non_empty + 1 ), ( $close_parenthesis + 1 ), true );

		if ( $next_next_non_empty === $close_parenthesis ) {
			// No parameters.
			return false;
		}

		return true;
	}

Checks if a function call has parameters.

Expects to be passed the T_STRING stack pointer for the function call.
If passed a T_STRING which is *not* a function call, the behaviour is unreliable.

Extra feature: If passed an T_ARRAY or T_OPEN_SHORT_ARRAY stack pointer, it
will detect whether the array has values or is empty.

@link https://github.com/PHPCompatibility/PHPCompatibility/issues/120
@link https://github.com/PHPCompatibility/PHPCompatibility/issues/152

@since 0.11.0

@param int $stackPtr The position of the function call token.

@return bool

Checks if a function call has parameters .


public function get_function_call_parameter_count( $stackPtr ) {
		if ( false === $this->does_function_call_have_parameters( $stackPtr ) ) {
			return 0;
		}

		return \count( $this->get_function_call_parameters( $stackPtr ) );
	}

public function get_function_call_parameter_count ( $ stackPtr ) { if ( false === $ this -> does_function_call_have_parameters ( $ stackPtr ) ) { return 0 ; } return \ count ( $ this -> get_function_call_parameters ( $ stackPtr ) ) ; }

Count the number of parameters a function call has been passed.

Expects to be passed the T_STRING stack pointer for the function call.
If passed a T_STRING which is *not* a function call, the behaviour is unreliable.

Extra feature: If passed an T_ARRAY or T_OPEN_SHORT_ARRAY stack pointer,
it will return the number of values in the array.

@link https://github.com/PHPCompatibility/PHPCompatibility/issues/111
@link https://github.com/PHPCompatibility/PHPCompatibility/issues/114
@link https://github.com/PHPCompatibility/PHPCompatibility/issues/151

@since 0.11.0

@param int $stackPtr The position of the function call token.

@return int

Count the number of parameters a function call has been passed .


public function get_function_call_parameter( $stackPtr, $param_offset ) {
		$parameters = $this->get_function_call_parameters( $stackPtr );

		if ( false === isset( $parameters[ $param_offset ] ) ) {
			return false;
		}

		return $parameters[ $param_offset ];
	}

public function get_function_call_parameter ( $ stackPtr , $ param_offset ) { $ parameters = $ this -> get_function_call_parameters ( $ stackPtr ) ; if ( false === isset ( $ parameters [ $ param_offset ] ) ) { return false ; } return $ parameters [ $ param_offset ] ; }

Get information on a specific parameter passed to a function call.

Expects to be passed the T_STRING stack pointer for the function call.
If passed a T_STRING which is *not* a function call, the behaviour is unreliable.

Will return a array with the start token pointer, end token pointer and the raw value
of the parameter at a specific offset.
If the specified parameter is not found, will return false.

@since 0.11.0

@param int $stackPtr     The position of the function call token.
@param int $param_offset The 1-based index position of the parameter to retrieve.

@return array|false

Get information on a specific parameter passed to a function call .


protected function find_array_open_close( $stackPtr ) {
		/*
		 * Determine the array opener & closer.
		 */
		if ( \T_ARRAY === $this->tokens[ $stackPtr ]['code'] ) {
			if ( isset( $this->tokens[ $stackPtr ]['parenthesis_opener'] ) ) {
				$opener = $this->tokens[ $stackPtr ]['parenthesis_opener'];

				if ( isset( $this->tokens[ $opener ]['parenthesis_closer'] ) ) {
					$closer = $this->tokens[ $opener ]['parenthesis_closer'];
				}
			}
		} else {
			// Short array syntax.
			$opener = $stackPtr;

			if ( isset( $this->tokens[ $stackPtr ]['bracket_closer'] ) ) {
				$closer = $this->tokens[ $stackPtr ]['bracket_closer'];
			}
		}

		if ( isset( $opener, $closer ) ) {
			return array(
				'opener' => $opener,
				'closer' => $closer,
			);
		}

		return false;
	}

Find the array opener & closer based on a T_ARRAY or T_OPEN_SHORT_ARRAY token.

@since 0.12.0

@param int $stackPtr The stack pointer to the array token.

@return array|bool Array with two keys `opener`, `closer` or false if
either or these could not be determined.

Find the array opener & closer based on a T_ARRAY or T_OPEN_SHORT_ARRAY token .


public function determine_namespace( $stackPtr ) {

		// Check for the existence of the token.
		if ( ! isset( $this->tokens[ $stackPtr ] ) ) {
			return '';
		}

		// Check for scoped namespace {}.
		if ( ! empty( $this->tokens[ $stackPtr ]['conditions'] ) ) {
			$namespacePtr = $this->phpcsFile->getCondition( $stackPtr, \T_NAMESPACE );
			if ( false !== $namespacePtr ) {
				$namespace = $this->get_declared_namespace_name( $namespacePtr );
				if ( false !== $namespace ) {
					return $namespace;
				}

				// We are in a scoped namespace, but couldn't determine the name.
				// Searching for a global namespace is futile.
				return '';
			}
		}

		/*
		 * Not in a scoped namespace, so let's see if we can find a non-scoped namespace instead.
		 * Keeping in mind that:
		 * - there can be multiple non-scoped namespaces in a file (bad practice, but it happens).
		 * - the namespace keyword can also be used as part of a function/method call and such.
		 * - that a non-named namespace resolves to the global namespace.
		 */
		$previousNSToken = $stackPtr;
		$namespace       = false;
		do {
			$previousNSToken = $this->phpcsFile->findPrevious( \T_NAMESPACE, ( $previousNSToken - 1 ) );

			// Stop if we encounter a scoped namespace declaration as we already know we're not in one.
			if ( ! empty( $this->tokens[ $previousNSToken ]['scope_condition'] )
				&& $this->tokens[ $previousNSToken ]['scope_condition'] === $previousNSToken
			) {
				break;
			}

			$namespace = $this->get_declared_namespace_name( $previousNSToken );

		} while ( false === $namespace && false !== $previousNSToken );

		// If we still haven't got a namespace, return an empty string.
		if ( false === $namespace ) {
			return '';
		}

		return $namespace;
	}

Determine the namespace name an arbitrary token lives in.

@since 0.10.0
@since 0.12.0 Moved from the `AbstractClassRestrictionsSniff` to this class.

@param int $stackPtr The token position for which to determine the namespace.

@return string Namespace name or empty string if it couldn't be determined or no namespace applies.

Determine the namespace name an arbitrary token lives in .


public function get_declared_namespace_name( $stackPtr ) {

		// Check for the existence of the token.
		if ( false === $stackPtr || ! isset( $this->tokens[ $stackPtr ] ) ) {
			return false;
		}

		if ( \T_NAMESPACE !== $this->tokens[ $stackPtr ]['code'] ) {
			return false;
		}

		$nextToken = $this->phpcsFile->findNext( Tokens::$emptyTokens, ( $stackPtr + 1 ), null, true, null, true );
		if ( \T_NS_SEPARATOR === $this->tokens[ $nextToken ]['code'] ) {
			// Not a namespace declaration, but use of, i.e. `namespace\someFunction();`.
			return false;
		}

		if ( \T_OPEN_CURLY_BRACKET === $this->tokens[ $nextToken ]['code'] ) {
			// Declaration for global namespace when using multiple namespaces in a file.
			// I.e.: `namespace {}`.
			return '';
		}

		// Ok, this should be a namespace declaration, so get all the parts together.
		$acceptedTokens = array(
			\T_STRING       => true,
			\T_NS_SEPARATOR => true,
		);
		$validTokens    = $acceptedTokens + Tokens::$emptyTokens;

		$namespaceName = '';
		while ( isset( $validTokens[ $this->tokens[ $nextToken ]['code'] ] ) ) {
			if ( isset( $acceptedTokens[ $this->tokens[ $nextToken ]['code'] ] ) ) {
				$namespaceName .= trim( $this->tokens[ $nextToken ]['content'] );
			}
			++$nextToken;
		}

		return $namespaceName;
	}

Get the complete namespace name for a namespace declaration.

For hierarchical namespaces, the name will be composed of several tokens,
i.e. MyProject\Sub\Level which will be returned together as one string.

@since 0.12.0 A lesser variant of this method previously existed in the
`AbstractClassRestrictionsSniff` class.

@param int|bool $stackPtr The position of a T_NAMESPACE token.

@return string|false Namespace name or false if not a namespace declaration.
Namespace name can be an empty string for global namespace declaration.

Get the complete namespace name for a namespace declaration .


public function is_class_constant( $stackPtr ) {
		if ( ! isset( $this->tokens[ $stackPtr ] ) || \T_CONST !== $this->tokens[ $stackPtr ]['code'] ) {
			return false;
		}

		// Note: traits can not declare constants.
		$valid_scopes = array(
			'T_CLASS'      => true,
			'T_ANON_CLASS' => true,
			'T_INTERFACE'  => true,
		);

		return is_int( $this->valid_direct_scope( $stackPtr, $valid_scopes ) );
	}

Check whether a T_CONST token is a class constant declaration.

@since 0.14.0

@param int $stackPtr  The position in the stack of the T_CONST token to verify.

@return bool

Check whether a T_CONST token is a class constant declaration .


public function is_class_property( $stackPtr ) {
		if ( ! isset( $this->tokens[ $stackPtr ] ) || \T_VARIABLE !== $this->tokens[ $stackPtr ]['code'] ) {
			return false;
		}

		// Note: interfaces can not declare properties.
		$valid_scopes = array(
			'T_CLASS'      => true,
			'T_ANON_CLASS' => true,
			'T_TRAIT'      => true,
		);

		$scopePtr = $this->valid_direct_scope( $stackPtr, $valid_scopes );
		if ( false !== $scopePtr ) {
			// Make sure it's not a method parameter.
			if ( empty( $this->tokens[ $stackPtr ]['nested_parenthesis'] ) ) {
				return true;
			} else {
				$parenthesis  = array_keys( $this->tokens[ $stackPtr ]['nested_parenthesis'] );
				$deepest_open = array_pop( $parenthesis );
				if ( $deepest_open < $scopePtr
					|| isset( $this->tokens[ $deepest_open ]['parenthesis_owner'] ) === false
					|| \T_FUNCTION !== $this->tokens[ $this->tokens[ $deepest_open ]['parenthesis_owner'] ]['code']
				) {
					return true;
				}
			}
		}

		return false;
	}

Check whether a T_VARIABLE token is a class property declaration.

@since 0.14.0

@param int $stackPtr  The position in the stack of the T_VARIABLE token to verify.

@return bool

Check whether a T_VARIABLE token is a class property declaration .


protected function valid_direct_scope( $stackPtr, array $valid_scopes ) {
		if ( empty( $this->tokens[ $stackPtr ]['conditions'] ) ) {
			return false;
		}

		/*
		 * Check only the direct wrapping scope of the token.
		 */
		$conditions = array_keys( $this->tokens[ $stackPtr ]['conditions'] );
		$ptr        = array_pop( $conditions );

		if ( ! isset( $this->tokens[ $ptr ] ) ) {
			return false;
		}

		if ( isset( $valid_scopes[ $this->tokens[ $ptr ]['type'] ] ) ) {
			return $ptr;
		}

		return false;
	}

Check whether the direct wrapping scope of a token is within a limited set of
acceptable tokens.

Used to check, for instance, if a T_CONST is a class constant.

@since 0.14.0

@param int   $stackPtr     The position in the stack of the token to verify.
@param array $valid_scopes Array of token types.
Keys should be the token types in string format
to allow for newer token types.
Value is irrelevant.

@return int|bool StackPtr to the scope if valid, false otherwise.

Check whether the direct wrapping scope of a token is within a limited set of acceptable tokens .


protected function prepare_regex() {
		$extra = '';
		if ( '' !== $this->additionalWordDelimiters && \is_string( $this->additionalWordDelimiters ) ) {
			$extra = preg_quote( $this->additionalWordDelimiters, '`' );
		}

		return sprintf( $this->punctuation_regex, $extra );
	}

protected function prepare_regex ( ) { $ extra = '' ; if ( '' !== $ this -> additionalWordDelimiters && \ is_string ( $ this -> additionalWordDelimiters ) ) { $ extra = preg_quote ( $ this -> additionalWordDelimiters , '`' ) ; } return sprintf ( $ this -> punctuation_regex , $ extra ) ; }

Prepare the punctuation regular expression.

Merges the existing regular expression with potentially provided extra word delimiters to allow.
This is done 'late' and for each found token as otherwise inline `phpcs:set` directives
would be ignored.

@return string

Prepare the punctuation regular expression .


protected function transform( $string, $regex, $transform_type = 'full' ) {

		switch ( $transform_type ) {
			case 'case':
				return strtolower( $string );

			case 'punctuation':
				return preg_replace( $regex, '_', $string );

			case 'full':
			default:
				return preg_replace( $regex, '_', strtolower( $string ) );
		}
	}

protected function transform ( $ string , $ regex , $ transform_type = 'full' ) { switch ( $ transform_type ) { case 'case' : return strtolower ( $ string ) ; case 'punctuation' : return preg_replace ( $ regex , '_' , $ string ) ; case 'full' : default : return preg_replace ( $ regex , '_' , strtolower ( $ string ) ) ; } }

Transform an arbitrary string to lowercase and replace punctuation and spaces with underscores.

@param string $string         The target string.
@param string $regex          The punctuation regular expression to use.
@param string $transform_type Whether to a partial or complete transform.
Valid values are: 'full', 'case', 'punctuation'.
@return string

Transform an arbitrary string to lowercase and replace punctuation and spaces with underscores .


protected function transform_complex_string( $string, $regex, $transform_type = 'full' ) {
		$output = preg_split( '`([\{\}\$\[\] ])`', $string, -1, \PREG_SPLIT_DELIM_CAPTURE );

		$is_variable = false;
		$has_braces  = false;
		$braces      = 0;

		foreach ( $output as $i => $part ) {
			if ( \in_array( $part, array( '$', '{' ), true ) ) {
				$is_variable = true;
				if ( '{' === $part ) {
					$has_braces = true;
					$braces++;
				}
				continue;
			}

			if ( true === $is_variable ) {
				if ( '[' === $part ) {
					$has_braces = true;
					$braces++;
				}
				if ( \in_array( $part, array( '}', ']' ), true ) ) {
					$braces--;
				}
				if ( false === $has_braces && ' ' === $part ) {
					$is_variable  = false;
					$output[ $i ] = $this->transform( $part, $regex, $transform_type );
				}

				if ( ( true === $has_braces && 0 === $braces ) && false === \in_array( $output[ ( $i + 1 ) ], array( '{', '[' ), true ) ) {
					$has_braces  = false;
					$is_variable = false;
				}
				continue;
			}

			$output[ $i ] = $this->transform( $part, $regex, $transform_type );
		}

		return implode( '', $output );
	}

protected
function
transform_complex_string
(
$
string
,
$
regex
,
$
transform_type
=
'full'
)
{
$
output
=
preg_split
(
'`([\{\}\$\[\] ])`'
,
$
string
,
1
,
\
PREG_SPLIT_DELIM_CAPTURE
)
;
$
is_variable
=
false
;
$
has_braces
=
false
;
$
braces
=
0
;
foreach
(
$
output
as
$
i
=>
$
part
)
{
if
(
\
in_array
(
$
part
,
array
(
'$'
,
'{'
)
,
true
)
)
{
$
is_variable
=
true
;
if
(
'{'
===
$
part
)
{
$
has_braces
=
true
;
$
braces
++
;
}
continue
;
}
if
(
true
===
$
is_variable
)
{
if
(
'['
===
$
part
)
{
$
has_braces
=
true
;
$
braces
++
;
}
if
(
\
in_array
(
$
part
,
array
(
'}'
,
']'
)
,
true
)
)
{
$
braces
;
}
if
(
false
===
$
has_braces
&&
' '
===
$
part
)
{
$
is_variable
=
false
;
$
output
[
$
i
]
=
$
this
->
transform
(
$
part
,
$
regex
,
$
transform_type
)
;
}
if
(
(
true
===
$
has_braces
&&
0
===
$
braces
)
&&
false
===
\
in_array
(
$
output
[
(
$
i
+
1
)
]
,
array
(
'{'
,
'['
)
,
true
)
)
{
$
has_braces
=
false
;
$
is_variable
=
false
;
}
continue
;
}
$
output
[
$
i
]
=
$
this
->
transform
(
$
part
,
$
regex
,
$
transform_type
)
;
}
return
implode
(
''
,
$
output
)
;
}

Transform a complex string which may contain variable extrapolation.

@param string $string         The target string.
@param string $regex          The punctuation regular expression to use.
@param string $transform_type Whether to a partial or complete transform.
Valid values are: 'full', 'case', 'punctuation'.
@return string

Transform a complex string which may contain variable extrapolation .


public function getGroups() {
		// Make sure all array keys are lowercase.
		$this->deprecated_classes = array_change_key_case( $this->deprecated_classes, CASE_LOWER );

		return array(
			'deprecated_classes' => array(
				'classes' => array_keys( $this->deprecated_classes ),
			),
		);
	}

Groups of classes to restrict.

@return array


public function process_arbitrary_tstring( $stackPtr ) {
		$content = $this->tokens[ $stackPtr ]['content'];

		if ( ! isset( $this->discouraged_constants[ $content ] ) ) {
			return;
		}

		$next = $this->phpcsFile->findNext( Tokens::$emptyTokens, ( $stackPtr + 1 ), null, true );
		if ( false !== $next && \T_OPEN_PARENTHESIS === $this->tokens[ $next ]['code'] ) {
			// Function call or declaration.
			return;
		}

		$prev = $this->phpcsFile->findPrevious( Tokens::$emptyTokens, ( $stackPtr - 1 ), null, true );
		if ( false !== $prev && isset( $this->preceding_tokens_to_ignore[ $this->tokens[ $prev ]['code'] ] ) ) {
			// Not the use of a constant.
			return;
		}

		if ( $this->is_token_namespaced( $stackPtr ) === true ) {
			// Namespaced constant of the same name.
			return;
		}

		if ( false !== $prev
			&& \T_CONST === $this->tokens[ $prev ]['code']
			&& true === $this->is_class_constant( $prev )
		) {
			// Class constant of the same name.
			return;
		}

		/*
		 * Deal with a number of variations of use statements.
		 */
		for ( $i = $stackPtr; $i > 0; $i-- ) {
			if ( $this->tokens[ $i ]['line'] !== $this->tokens[ $stackPtr ]['line'] ) {
				break;
			}
		}

		$first_on_line = $this->phpcsFile->findNext( Tokens::$emptyTokens, ( $i + 1 ), null, true );
		if ( false !== $first_on_line && \T_USE === $this->tokens[ $first_on_line ]['code'] ) {
			$next_on_line = $this->phpcsFile->findNext( Tokens::$emptyTokens, ( $first_on_line + 1 ), null, true );
			if ( false !== $next_on_line ) {
				if ( ( \T_STRING === $this->tokens[ $next_on_line ]['code']
						&& 'const' === $this->tokens[ $next_on_line ]['content'] )
					|| \T_CONST === $this->tokens[ $next_on_line ]['code'] // Happens in some PHPCS versions.
				) {
					$has_ns_sep = $this->phpcsFile->findNext( \T_NS_SEPARATOR, ( $next_on_line + 1 ), $stackPtr );
					if ( false !== $has_ns_sep ) {
						// Namespaced const (group) use statement.
						return;
					}
				} else {
					// Not a const use statement.
					return;
				}
			}
		}

		// Ok, this is really one of the discouraged constants.
		$this->phpcsFile->addWarning(
			'Found usage of constant "%s". Use %s instead.',
			$stackPtr,
			$this->string_to_errorcode( $content . 'UsageFound' ),
			array(
				$content,
				$this->discouraged_constants[ $content ],
			)
		);
	}

Process an arbitrary T_STRING token to determine whether it is one of the target constants.

@since 0.14.0

@param int $stackPtr The position of the current token in the stack.

@return void

Process an arbitrary T_STRING token to determine whether it is one of the target constants .


public function process_parameters( $stackPtr, $group_name, $matched_content, $parameters ) {
		$function_name = strtolower( $matched_content );
		$target_param  = $this->target_functions[ $function_name ];

		// Was the target parameter passed ?
		if ( ! isset( $parameters[ $target_param ] ) ) {
			return;
		}

		$raw_content = $this->strip_quotes( $parameters[ $target_param ]['raw'] );

		if ( isset( $this->discouraged_constants[ $raw_content ] ) ) {
			$this->phpcsFile->addWarning(
				'Found declaration of constant "%s". Use %s instead.',
				$stackPtr,
				$this->string_to_errorcode( $raw_content . 'DeclarationFound' ),
				array(
					$raw_content,
					$this->discouraged_constants[ $raw_content ],
				)
			);
		}
	}

Process the parameters of a matched `define` function call.

@since 0.14.0

@param int    $stackPtr        The position of the current token in the stack.
@param array  $group_name      The name of the group which was matched.
@param string $matched_content The token content (function name) which was matched.
@param array  $parameters      Array with information about the parameters.

@return void

Process the parameters of a matched define function call .


protected function retrieve_misspellings( $match_stack ) {
		$mispelled = array();
		foreach ( $match_stack as $match ) {
			// Deal with multi-dimensional arrays when capturing offset.
			if ( \is_array( $match ) ) {
				$match = $match[0];
			}

			if ( 'WordPress' !== $match ) {
				$mispelled[] = $match;
			}
		}

		return $mispelled;
	}

Retrieve a list of misspellings based on an array of matched variations on the target word.

@param array $match_stack Array of matched variations of the target word.
@return array Array containing only the misspelled variants.

Retrieve a list of misspellings based on an array of matched variations on the target word .


public function callback( $key, $val, $line, $group ) {
		$this->posts_per_page = (int) $this->posts_per_page;

		if ( $val > $this->posts_per_page ) {
			return 'Detected high pagination limit, `%s` is set to `%s`';
		}

		return false;
	}

Callback to process each confirmed key, to check value.

@param  string $key   Array index / key.
@param  mixed  $val   Assigned value.
@param  int    $line  Token line.
@param  array  $group Group definition.
@return mixed         FALSE if no match, TRUE if matches, STRING if matches
with custom error message passed to ->process().

Callback to process each confirmed key to check value .


public static function set_config_data( $key, $value, $temp = false ) {
		Config::setConfigData( $key, $value, $temp );
	}

public static function set_config_data ( $ key , $ value , $ temp = false ) { Config :: setConfigData ( $ key , $ value , $ temp ) ; }

Pass config data to PHPCS.

PHPCS cross-version compatibility helper.

@since 0.13.0

@param string      $key   The name of the config value.
@param string|null $value The value to set. If null, the config entry
is deleted, reverting it to the default value.
@param boolean     $temp  Set this config data temporarily for this script run.
This will not write the config data to the config file.


public static function get_tab_width( File $phpcsFile ) {
		$tab_width = 4;

		if ( isset( $phpcsFile->config->tabWidth ) && $phpcsFile->config->tabWidth > 0 ) {
			$tab_width = $phpcsFile->config->tabWidth;
		}

		return $tab_width;
	}

public static function get_tab_width ( File $ phpcsFile ) { $ tab_width = 4 ; if ( isset ( $ phpcsFile -> config -> tabWidth ) && $ phpcsFile -> config -> tabWidth > 0 ) { $ tab_width = $ phpcsFile -> config -> tabWidth ; } return $ tab_width ; }

Get the tab width as passed to PHPCS from the command-line or the ruleset.

@since 0.13.0

@param \PHP_CodeSniffer\Files\File $phpcsFile The file being processed.

@return int Tab width. Defaults to 4.

Get the tab width as passed to PHPCS from the command - line or the ruleset .


protected function process_global_statement( $stackPtr, $in_function_scope ) {
		/*
		 * Collect the variables to watch for.
		 */
		$search = array();
		$ptr    = ( $stackPtr + 1 );
		while ( isset( $this->tokens[ $ptr ] ) ) {
			$var = $this->tokens[ $ptr ];

			// Halt the loop at end of statement.
			if ( \T_SEMICOLON === $var['code'] ) {
				break;
			}

			if ( \T_VARIABLE === $var['code'] ) {
				if ( isset( $this->wp_globals[ substr( $var['content'], 1 ) ] ) ) {
					$search[] = $var['content'];
				}
			}

			$ptr++;
		}
		unset( $var );

		if ( empty( $search ) ) {
			return;
		}

		/*
		 * Search for assignments to the imported global variables within the relevant scope.
		 */
		$start = $ptr;
		if ( true === $in_function_scope ) {
			$function_cond = $this->phpcsFile->getCondition( $stackPtr, \T_FUNCTION );
			$closure_cond  = $this->phpcsFile->getCondition( $stackPtr, \T_CLOSURE );
			$scope_cond    = max( $function_cond, $closure_cond ); // If false, it will evaluate as zero, so this is fine.
			if ( isset( $this->tokens[ $scope_cond ]['scope_closer'] ) === false ) {
				// Live coding or parse error.
				return;
			}
			$end = $this->tokens[ $scope_cond ]['scope_closer'];
		} else {
			// Global statement in the global namespace with file is being treated as scoped.
			$end = ( $this->phpcsFile->numTokens + 1 );
		}

		for ( $ptr = $start; $ptr < $end; $ptr++ ) {

			// Skip over nested functions, classes and the likes.
			if ( isset( $this->skip_over[ $this->tokens[ $ptr ]['code'] ] ) ) {
				if ( ! isset( $this->tokens[ $ptr ]['scope_closer'] ) ) {
					// Live coding or parse error.
					break;
				}

				$ptr = $this->tokens[ $ptr ]['scope_closer'];
				continue;
			}

			if ( \T_VARIABLE !== $this->tokens[ $ptr ]['code'] ) {
				continue;
			}

			if ( \in_array( $this->tokens[ $ptr ]['content'], $search, true ) === false ) {
				// Not one of the variables we're interested in.
				continue;
			}

			// Don't throw false positives for static class properties.
			if ( $this->is_class_object_call( $ptr ) === true ) {
				continue;
			}

			if ( true === $this->is_assignment( $ptr ) ) {
				$this->maybe_add_error( $ptr );
				continue;
			}

			// Check if this is a variable assignment within a `foreach()` declaration.
			if ( $this->is_foreach_as( $ptr ) === true ) {
				$this->maybe_add_error( $ptr );
			}
		}
	}

Check that global variables imported into a function scope using a global statement
are not being overruled.

@since 1.1.0 Logic was previously contained in the process_token() method.

@param int  $stackPtr          The position of the current token in the stack.
@param bool $in_function_scope Whether the global statement is within a scoped function/closure.

@return void

Check that global variables imported into a function scope using a global statement are not being overruled .


protected function add_error( $stackPtr, $data = array() ) {
		if ( empty( $data ) ) {
			$data[] = $this->tokens[ $stackPtr ]['content'];
		}

		$this->phpcsFile->addError(
			'Overriding WordPress globals is prohibited. Found assignment to %s',
			$stackPtr,
			'Prohibited',
			$data
		);
	}

Add the error.

@since 1.1.0

@param int   $stackPtr The position of the token to throw the error for.
@param array $data     Optional. Array containing one entry holding the
name of the variable being overruled.
Defaults to the 'content' of the $stackPtr token.

@return void


protected function setup_groups( $key ) {
		// Prepare the function group regular expressions only once.
		$this->groups = $this->getGroups();

		if ( empty( $this->groups ) && empty( self::$unittest_groups ) ) {
			return false;
		}

		// Allow for adding extra unit tests.
		if ( ! empty( self::$unittest_groups ) ) {
			$this->groups = array_merge( $this->groups, self::$unittest_groups );
		}

		$all_items = array();
		foreach ( $this->groups as $groupName => $group ) {
			if ( empty( $group[ $key ] ) ) {
				unset( $this->groups[ $groupName ] );
			} else {
				$items       = array_map( array( $this, 'prepare_name_for_regex' ), $group[ $key ] );
				$all_items[] = $items;
				$items       = implode( '|', $items );

				$this->groups[ $groupName ]['regex'] = sprintf( $this->regex_pattern, $items );
			}
		}

		if ( empty( $this->groups ) ) {
			return false;
		}

		// Create one "super-regex" to allow for initial filtering.
		$all_items                = \call_user_func_array( 'array_merge', $all_items );
		$all_items                = implode( '|', array_unique( $all_items ) );
		$this->prelim_check_regex = sprintf( $this->regex_pattern, $all_items );

		return true;
	}

Set up the regular expressions for each group.

@since 0.10.0

@param string $key The group array index key where the input for the regular expression can be found.
@return bool True if the groups were setup. False if not.

Set up the regular expressions for each group .


public function is_targetted_token( $stackPtr ) {

		// Exclude function definitions, class methods, and namespaced calls.
		if ( \T_STRING === $this->tokens[ $stackPtr ]['code'] ) {
			if ( $this->is_class_object_call( $stackPtr ) === true ) {
				return false;
			}

			if ( $this->is_token_namespaced( $stackPtr ) === true ) {
				return false;
			}

			$prev = $this->phpcsFile->findPrevious( Tokens::$emptyTokens, ( $stackPtr - 1 ), null, true );

			if ( false !== $prev ) {
				// Skip sniffing if calling a same-named method, or on function definitions.
				$skipped = array(
					\T_FUNCTION        => \T_FUNCTION,
					\T_CLASS           => \T_CLASS,
					\T_AS              => \T_AS, // Use declaration alias.
				);

				if ( isset( $skipped[ $this->tokens[ $prev ]['code'] ] ) ) {
					return false;
				}
			}

			return true;
		}

		return false;
	}

Verify is the current token is a function call.

@since 0.11.0 Split out from the `process()` method.

@param int $stackPtr The position of the current token in the stack.

@return bool

Verify is the current token is a function call .


public function check_for_matches( $stackPtr ) {
		$token_content = strtolower( $this->tokens[ $stackPtr ]['content'] );
		$skip_to       = array();

		foreach ( $this->groups as $groupName => $group ) {

			if ( isset( $this->excluded_groups[ $groupName ] ) ) {
				continue;
			}

			if ( isset( $group['whitelist'][ $token_content ] ) ) {
				continue;
			}

			if ( preg_match( $group['regex'], $token_content ) === 1 ) {
				$skip_to[] = $this->process_matched_token( $stackPtr, $groupName, $token_content );
			}
		}

		if ( empty( $skip_to ) || min( $skip_to ) === 0 ) {
			return;
		}

		return min( $skip_to );
	}

public function check_for_matches ( $ stackPtr ) { $ token_content = strtolower ( $ this -> tokens [ $ stackPtr ] [ 'content' ] ) ; $ skip_to = array ( ) ; foreach ( $ this -> groups as $ groupName => $ group ) { if ( isset ( $ this -> excluded_groups [ $ groupName ] ) ) { continue ; } if ( isset ( $ group [ 'whitelist' ] [ $ token_content ] ) ) { continue ; } if ( preg_match ( $ group [ 'regex' ] , $ token_content ) === 1 ) { $ skip_to [ ] = $ this -> process_matched_token ( $ stackPtr , $ groupName , $ token_content ) ; } } if ( empty ( $ skip_to ) || min ( $ skip_to ) === 0 ) { return ; } return min ( $ skip_to ) ; }

Verify if the current token is one of the targetted functions.

@since 0.11.0 Split out from the `process()` method.

@param int $stackPtr The position of the current token in the stack.

@return int|void Integer stack pointer to skip forward or void to continue
normal file processing.

Verify if the current token is one of the targetted functions .


protected function process_variable_variable( $stackPtr ) {
		static $indicators = array(
			\T_OPEN_CURLY_BRACKET => true,
			\T_VARIABLE           => true,
		);

		// Is this a variable variable ?
		// Not concerned with nested ones as those will be recognized on their own token.
		$next_non_empty = $this->phpcsFile->findNext( Tokens::$emptyTokens, ( $stackPtr + 1 ), null, true, null, true );
		if ( false === $next_non_empty || ! isset( $indicators[ $this->tokens[ $next_non_empty ]['code'] ] ) ) {
			return;
		}

		if ( \T_OPEN_CURLY_BRACKET === $this->tokens[ $next_non_empty ]['code']
			&& isset( $this->tokens[ $next_non_empty ]['bracket_closer'] )
		) {
			// Skip over the variable part.
			$next_non_empty = $this->tokens[ $next_non_empty ]['bracket_closer'];
		}

		$maybe_assignment = $this->phpcsFile->findNext( Tokens::$emptyTokens, ( $next_non_empty + 1 ), null, true, null, true );

		while ( false !== $maybe_assignment
			&& \T_OPEN_SQUARE_BRACKET === $this->tokens[ $maybe_assignment ]['code']
			&& isset( $this->tokens[ $maybe_assignment ]['bracket_closer'] )
		) {
			$maybe_assignment = $this->phpcsFile->findNext(
				Tokens::$emptyTokens,
				( $this->tokens[ $maybe_assignment ]['bracket_closer'] + 1 ),
				null,
				true,
				null,
				true
			);
		}

		if ( false === $maybe_assignment ) {
			return;
		}

		if ( ! isset( Tokens::$assignmentTokens[ $this->tokens[ $maybe_assignment ]['code'] ] ) ) {
			// Not an assignment.
			return;
		}

		$error = self::ERROR_MSG;

		/*
		 * Local variable variables in a function do not need to be prefixed.
		 * But a variable variable could evaluate to the name of an imported global
		 * variable.
		 * Not concerned with imported variable variables (global.. ) as that has been
		 * forbidden since PHP 7.0. Presuming cross-version code and if not, that
		 * is for the PHPCompatibility standard to detect.
		 */
		if ( $this->phpcsFile->hasCondition( $stackPtr, array( \T_FUNCTION, \T_CLOSURE ) ) === true ) {
			$condition = $this->phpcsFile->getCondition( $stackPtr, \T_FUNCTION );
			if ( false === $condition ) {
				$condition = $this->phpcsFile->getCondition( $stackPtr, \T_CLOSURE );
			}

			$has_global = $this->phpcsFile->findPrevious( \T_GLOBAL, ( $stackPtr - 1 ), $this->tokens[ $condition ]['scope_opener'] );
			if ( false === $has_global ) {
				// No variable import happening.
				return;
			}

			$error = 'Variable variable which could potentially override an imported global variable detected. ' . $error;
		}

		$variable_name = $this->phpcsFile->getTokensAsString( $stackPtr, ( ( $next_non_empty - $stackPtr ) + 1 ) );

		// Still here ? In that case, the variable name should be prefixed.
		$recorded = $this->phpcsFile->addWarning(
			$error,
			$stackPtr,
			'NonPrefixedVariableFound',
			array(
				'Global variables defined',
				$variable_name,
			)
		);

		if ( true === $recorded ) {
			$this->record_potential_prefix_metric( $stackPtr, $variable_name );
		}

		// Skip over the variable part of the variable.
		return ( $next_non_empty + 1 );
	}

Handle variable variables defined in the global namespace.

@since 0.12.0

@param int $stackPtr The position of the current token in the stack.

@return int|void Integer stack pointer to skip forward or void to continue
normal file processing.

Handle variable variables defined in the global namespace .


private function variable_prefixed_or_whitelisted( $stackPtr, $name ) {
		// Ignore superglobals and WP global variables.
		if ( isset( $this->superglobals[ $name ] ) || isset( $this->wp_globals[ $name ] ) ) {
			return true;
		}

		return $this->is_prefixed( $stackPtr, $name );
	}

Check if a variable name might need a prefix.

Prefix is not needed for:
- superglobals,
- WP native globals,
- variables which are already prefixed.

@since 0.12.0
@since 1.0.1  Added $stackPtr parameter.

@param int    $stackPtr The position of the token to record the metric against.
@param string $name     Variable name without the dollar sign.

@return bool True if the variable name is whitelisted or already prefixed.
False otherwise.

Check if a variable name might need a prefix .


private function validate_prefixes() {
		if ( $this->previous_prefixes === $this->prefixes ) {
			return;
		}

		// Set the cache *before* validation so as to not break the above compare.
		$this->previous_prefixes = $this->prefixes;

		// Validate the passed prefix(es).
		$prefixes    = array();
		$ns_prefixes = array();
		foreach ( $this->prefixes as $key => $prefix ) {
			$prefixLC = strtolower( $prefix );

			if ( isset( $this->prefix_blacklist[ $prefixLC ] ) ) {
				$this->phpcsFile->addError(
					'The "%s" prefix is not allowed.',
					0,
					'ForbiddenPrefixPassed',
					array( $prefix )
				);
				continue;
			}

			// Validate the prefix against characters allowed for function, class, constant names etc.
			if ( preg_match( '`^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff\\\\]*$`', $prefix ) !== 1 ) {
				$this->phpcsFile->addWarning(
					'The "%s" prefix is not a valid namespace/function/class/variable/constant prefix in PHP.',
					0,
					'InvalidPrefixPassed',
					array( $prefix )
				);
			}

			// Lowercase the prefix to allow for direct compare.
			$prefixes[ $key ] = $prefixLC;

			/*
			 * Replace non-word characters in the prefix with a regex snippet, but only if the
			 * string doesn't already contain namespace separators.
			 */
			$is_regex = false;
			if ( strpos( $prefix, '\\' ) === false && preg_match( '`[_\W]`', $prefix ) > 0 ) {
				$prefix   = preg_replace( '`([_\W])`', '[\\\\\\\\$1]', $prefixLC );
				$is_regex = true;
			}

			$ns_prefixes[ $prefixLC ] = array(
				'prefix'   => $prefix,
				'is_regex' => $is_regex,
			);
		}

		// Set the validated prefixes caches.
		$this->validated_prefixes           = $prefixes;
		$this->validated_namespace_prefixes = $ns_prefixes;
	}

Validate an array of prefixes as passed through a custom property or via the command line.

Checks that the prefix:
- is not one of the blacklisted ones.
- complies with the PHP rules for valid function, class, variable, constant names.

@since 0.12.0

Validate an array of prefixes as passed through a custom property or via the command line .