diff --git a/include/ajax.kbase.php b/include/ajax.kbase.php
index d6d30a1b0476072e0d9464ff9dc8cfde00296db8..1e642847bba383d986bafeadadee6370bcec54ed 100644
--- a/include/ajax.kbase.php
+++ b/include/ajax.kbase.php
@@ -32,6 +32,7 @@ class KbaseAjaxAPI extends AjaxController {
             $ticket = Ticket::lookup($_GET['tid']);
         }
 
+        $resp = array();
         switch($format) {
             case 'json':
                 $resp['id'] = $canned->getId();
diff --git a/include/ajax.tickets.php b/include/ajax.tickets.php
index c0f69e8a95c35c8546b6f9d67f9f1a7c4f314a5f..9910e27699590997a6528168bf291ca267058df3 100644
--- a/include/ajax.tickets.php
+++ b/include/ajax.tickets.php
@@ -236,6 +236,7 @@ class TicketsAjaxAPI extends AjaxController {
 
     function search() {
         $tickets = self::_search($_REQUEST);
+        $result = array();
 
         if (count($tickets)) {
             $uid = md5($_SERVER['QUERY_STRING']);
@@ -414,6 +415,8 @@ class TicketsAjaxAPI extends AjaxController {
             $ticket->getEmail());
         echo '
             </table>';
+
+        $options = array();
         $options[]=array('action'=>'Thread ('.$ticket->getThreadCount().')','url'=>"tickets.php?id=$tid");
         if($ticket->getNumNotes())
             $options[]=array('action'=>'Notes ('.$ticket->getNumNotes().')','url'=>"tickets.php?id=$tid#notes");
diff --git a/include/class.api.php b/include/class.api.php
index 6dec23efbc71969df796ecb8d9fc206f090b4129..23ae8a589e9192a08394134929ff9429695b2f30 100644
--- a/include/class.api.php
+++ b/include/class.api.php
@@ -396,7 +396,7 @@ class ApiJsonDataParser extends JsonDataParser {
                         "name" => key($info),
                     );
                 }
-                unset($value);
+                unset($info);
             }
             if (is_array($value)) {
                 $value = $this->fixup($value);
diff --git a/include/class.faq.php b/include/class.faq.php
index 7cb3c9a950ee9e2461fabf79d5f8b3ec57c07f62..4445a7cf7c9a262f0faf68e1e5bfa228ea062da6 100644
--- a/include/class.faq.php
+++ b/include/class.faq.php
@@ -130,8 +130,9 @@ class FAQ {
 
     /* Same as update - but mainly called after one or more setters are changed. */
     function apply() {
+        $errors = array();
         //XXX: set errors and add ->getErrors() & ->getError()
-        return $this->update($this->ht, $errors);               # nolint
+        return $this->update($this->ht, $errors);
     }
 
     function updateTopics($ids){
diff --git a/include/class.filter.php b/include/class.filter.php
index 81c6a39fe17a86e8e5981385a0dd417d6e47955f..15c68cc3170596abef12fb44e1eaf4365b7c447c 100644
--- a/include/class.filter.php
+++ b/include/class.filter.php
@@ -175,11 +175,12 @@ class Filter {
     }
 
     function addRule($what, $how, $val,$extra=array()) {
+        $errors = array();
 
         $rule= array_merge($extra,array('what'=>$what, 'how'=>$how, 'val'=>$val));
         $rule['filter_id']=$this->getId();
 
-        return FilterRule::create($rule,$errors);               # nolint
+        return FilterRule::create($rule,$errors);
     }
 
     function removeRule($what, $how, $val) {
@@ -512,7 +513,8 @@ class Filter {
 
         //Success with update/create...save the rules. We can't recover from any errors at this point.
         # Don't care about errors stashed in $xerrors
-        self::save_rules($id,$vars,$xerrors);               # nolint
+        $xerrors = array();
+        self::save_rules($id,$vars,$xerrors);
 
         return true;
     }
diff --git a/include/class.mailparse.php b/include/class.mailparse.php
index 08e2f92b04c38ba01caeb64d05ea3f9610ba462f..afc89008c32342f61c464c9962a5eabc4179cc16 100644
--- a/include/class.mailparse.php
+++ b/include/class.mailparse.php
@@ -60,7 +60,7 @@ class Mail_Parse {
     }
 
     function splitBodyHeader() {
-
+        $match = array();
         if (preg_match("/^(.*?)\r?\n\r?\n(.*)/s",
                 $this->mime_message,
                 $match)) {                                  # nolint
diff --git a/include/class.orm.php b/include/class.orm.php
index 90557fa7677df8c44dc68125c97ad8bfd72a9b86..05201c6682bc38cb4579b14492e6f62c3d7c406e 100644
--- a/include/class.orm.php
+++ b/include/class.orm.php
@@ -139,6 +139,7 @@ class VerySimpleModel {
     function delete($pk=false) {
         $table = static::$meta['table'];
         $sql = 'DELETE FROM '.$table;
+        $filter = array();
 
         if (!$pk) $pk = static::$meta['pk'];
         if (!is_array($pk)) $pk=array($pk);
@@ -626,7 +627,7 @@ class SqlCompiler {
     }
 
     function compileWhere($where, $model) {
-        $constrints = array();
+        $constraints = array();
         foreach ($where as $constraint) {
             $filter = array();
             foreach ($constraint as $field=>$value) {
diff --git a/include/class.pdf.php b/include/class.pdf.php
index b20eaf7ac53df9290a0532fafcb7ac62d466e491..cf17a2f7e4bc954c55a0bf807a3ff9b71f55b412 100644
--- a/include/class.pdf.php
+++ b/include/class.pdf.php
@@ -291,6 +291,7 @@ class Ticket2PDF extends FPDF
                 if($entry['attachments']
                         && ($tentry=$ticket->getThreadEntry($entry['id']))
                         && ($attachments = $tentry->getAttachments())) {
+                    $files = array();
                     foreach($attachments as $attachment)
                         $files[]= $attachment['name'];
 
diff --git a/include/class.thread.php b/include/class.thread.php
index eca16c58e595f57d597c4535658e36fb13e8e163..ef1d24ed8fdd15dc79d9e0013aadfca541ffc816 100644
--- a/include/class.thread.php
+++ b/include/class.thread.php
@@ -403,9 +403,7 @@ Class ThreadEntry {
             return null;
 
         $id=0;
-        if (!$attachment['error'] && ($id=$this->saveAttachment($attachment)))
-            $files[] = $id;
-        else {
+        if ($attachment['error'] || !($id=$this->saveAttachment($attachment))) {
             $error = $attachment['error'];
 
             if(!$error)
diff --git a/include/class.variable.php b/include/class.variable.php
index 3a71bd66de4239c47439cbd196061d1557ebf0f6..36d49e6a39accdcdee68aaa06cd8059779474e00 100644
--- a/include/class.variable.php
+++ b/include/class.variable.php
@@ -121,7 +121,9 @@ class VariableReplacer {
     function _parse($text) {
 
         $input = $text;
-        if(!preg_match_all('/'.$this->start_delim.'([A-Za-z_][\w._]+)'.$this->end_delim.'/', $input, $result))
+        $result = array();
+        if(!preg_match_all('/'.$this->start_delim.'([A-Za-z_][\w._]+)'.$this->end_delim.'/',
+                $input, $result))
             return null;
 
         $vars = array();
diff --git a/include/mysql.php b/include/mysql.php
index 4e3bd7eb8caf242c92b3846fb1b7d5c845f31a87..9e8194827bd997f00d1d5f9a2bd4c61305e008a8 100644
--- a/include/mysql.php
+++ b/include/mysql.php
@@ -51,6 +51,7 @@
     function db_version() {
 
         $version=0;
+        $matches = array();
         if(preg_match('/(\d{1,2}\.\d{1,2}\.\d{1,2})/',
                 mysql_result(db_query('SELECT VERSION()'),0,0),
                 $matches))                                      # nolint
@@ -129,6 +130,7 @@
     }
 
     function db_assoc_array($res, $mode=false) {
+        $result = array();
 	    if($res && db_num_rows($res)) {
       	    while ($row=db_fetch_array($res, $mode))
          	    $result[]=$row;
diff --git a/include/mysqli.php b/include/mysqli.php
index 06d4032fdc5419f3ffd24bd5a0fe6abe2ea46fb4..9d942eb51e2d0d9b1d343a2d3b82090a0d23a211 100644
--- a/include/mysqli.php
+++ b/include/mysqli.php
@@ -77,6 +77,7 @@ function db_close() {
 function db_version() {
 
     $version=0;
+    $matches = array();
     if(preg_match('/(\d{1,2}\.\d{1,2}\.\d{1,2})/',
             db_result(db_query('SELECT VERSION()')),
             $matches))                                      # nolint
@@ -165,6 +166,7 @@ function db_fetch_field($res) {
 }
 
 function db_assoc_array($res, $mode=false) {
+    $result = array();
     if($res && db_num_rows($res)) {
         while ($row=db_fetch_array($res, $mode))
             $result[]=$row;
diff --git a/setup/cli/modules/import.php b/setup/cli/modules/import.php
index e0f23d57a1a11e8b8b8c24df592edc4b36cd992e..84c27396d4b790c4a5612c2146490e5da42d9090 100644
--- a/setup/cli/modules/import.php
+++ b/setup/cli/modules/import.php
@@ -113,6 +113,7 @@ class Importer extends Module {
         $sql = 'CREATE TABLE `'.TABLE_PREFIX.$info[1].'` (';
         $pk = array();
         $fields = array();
+        $queries = array();
         foreach ($info[2] as $col) {
             $field = "`{$col['Field']}` {$col['Type']}";
             if ($col['Null'] == 'NO')
diff --git a/setup/test/tests/class.php_analyze.php b/setup/test/tests/class.php_analyze.php
new file mode 100644
index 0000000000000000000000000000000000000000..5ebcb37d524f5c9808bdaa4f5f4bf6f2b4328611
--- /dev/null
+++ b/setup/test/tests/class.php_analyze.php
@@ -0,0 +1,303 @@
+<?php
+require_once('class.test.php');
+
+$super_globals = array_fill_keys(
+    array('$_SERVER', '$_FILES', '$_SESSION', '$_GET', '$_POST',
+        '$_REQUEST', '$_ENV'), 1);
+
+class SourceAnalyzer extends Test {
+    var $bugs = array();
+    var $globals = array();
+    var $file = '';
+
+    function __construct($source) {
+        $this->tokens = token_get_all(file_get_contents($source));
+        $this->file = $source;
+    }
+
+    function parseFile() {
+
+        $this->checkVariableUsage(
+            array('line'=>array(0, $this->file), 'name'=>'(main)'),
+            array(),
+            1);
+    }
+
+    function traverseClass($line) {
+        $class = array('line'=>$line);
+        $token = false;
+        $blocks = 0;
+        while (list($i,$token) = each($this->tokens)) {
+            switch ($token[0]) {
+            case '{':
+                $blocks++;
+                break;
+            case '}':
+                if (--$blocks == 0)
+                    return;
+                break;
+            case T_STRING:
+                if (!isset($class['name']))
+                    $class['name'] = $token[1];
+                break;
+            case T_FUNCTION:
+                $this->traverseFunction(
+                    array($token[2], $line[1]),
+                    array('allow_this'=>true));
+                break;
+            case T_VAR:
+                // var $variable
+                // used inside classes to define instance variables
+                while (list(,$token) = each($this->tokens)) {
+                    if (is_array($token) && $token[0] == T_VARIABLE)
+                        // TODO: Add this to some class context in the
+                        // future to support indefined access to $this->blah
+                        break;
+                }
+                break;
+            }
+        }
+    }
+
+    function traverseFunction($line=0, $options=array()) {
+        // Scan for function name
+        $function = array('line'=>$line, 'name'=>'(inline)');
+        $token = false;
+        $scope = array();
+        while ($token != "{") {
+            list(,$token) = each($this->tokens);
+            if (!is_array($token)
+                    || $token[0] == T_WHITESPACE)
+                continue;
+            if ($token[0] == T_STRING)
+                $function['name'] = $token[1];
+            elseif ($token[0] == T_VARIABLE)
+                $scope[$token[1]] = 1;
+        }
+        // Start inside a block -- we've already consumed the {
+        $this->checkVariableUsage($function, $scope, 1, $options);
+    }
+
+    function checkVariableUsage($function, $scope=array(), $blocks=0,
+            $options=array()) {
+        global $super_globals;
+
+        // Merge in defaults to the options array
+        $options = array_merge(array(
+            'allow_this' => false,
+            ), $options);
+        // Unpack function[line][file] if set
+        if (is_array($function['line']))
+            $function['file'] = $function['line'][1];
+        while (list($i,$token) = each($this->tokens)) {
+            // Check variable usage and for nested blocks
+            switch ($token[0]) {
+            case '{':
+                $blocks++;
+                break;
+            case '}':
+                if (--$blocks == 0)
+                    return;
+                break;
+            case T_VARIABLE:
+                // Look-ahead for assignment
+                $assignment = false;
+                while ($next = @$this->tokens[++$i])
+                    if (!is_array($next) || $next[0] != T_WHITESPACE)
+                        break;
+                switch ($next[0]) {
+                case '=':
+                    // For assignment, check if the variable is explictly
+                    // assigned to NULL. If so, treat the assignment as an
+                    // unset()
+                    while ($next = @$this->tokens[++$i])
+                        if (!is_array($next) || $next[0] != T_WHITESPACE)
+                            break;
+                    if (is_array($next) && strcasecmp('NULL', $next[1]) === 0) {
+                        $scope[$token[1]] = 'null';
+                        $assignment = true;
+                        break;
+                    }
+                case T_AND_EQUAL:
+                case T_CONCAT_EQUAL:
+                case T_DIV_EQUAL:
+                case T_MINUS_EQUAL:
+                case T_MOD_EQUAL:
+                case T_MUL_EQUAL:
+                case T_OR_EQUAL:
+                case T_PLUS_EQUAL:
+                case T_SL_EQUAL:
+                case T_SR_EQUAL:
+                case T_XOR_EQUAL:
+                    $assignment = true;
+                    $scope[$token[1]] = 1;
+                    break;
+                }
+                if ($assignment)
+                    break;
+
+                if (!isset($scope[$token[1]])) {
+                    if ($token[1] == '$this' && $options['allow_this']) {
+                        // Always valid in a non-static class method
+                        // TODO: Determine if this function is defined in a class
+                        break;
+                    }
+                    elseif (isset($super_globals[$token[1]]))
+                        // Super globals are always in scope
+                        break;
+                    elseif (!isset($function['name']) || $function['name'] == '(main)')
+                        // Not in a function. Cowardly continue.
+                        // TODO: Recurse into require() statements to
+                        // determine if global variables are actually
+                        // defined somewhere in the code base
+                        break;
+                    $this->bugs[] = array(
+                        'type' => 'UNDEF_ACCESS',
+                        'func' => $function['name'],
+                        'line' => array($token[2], $function['file']),
+                        'name' => $token[1],
+                    );
+                }
+                elseif ($scope[$token[1]] == 'null') {
+                    // See if the next token is accessing a property of the
+                    // object
+                    $c = current($this->tokens);
+                    switch ($c[0]) {
+                    case T_OBJECT_OPERATOR:
+                    case T_PAAMAYIM_NEKUDOTAYIM:
+                    case '[':
+                        $this->bugs[] = array(
+                            'type' => 'MAYBE_UNDEF_ACCESS',
+                            'func' => $function['name'],
+                            'line' => array($token[2], $function['file']),
+                            'name' => $token[1],
+                        );
+                    }
+                }
+                break;
+            case T_PAAMAYIM_NEKUDOTAYIM:
+                // Handle static variables $instance::$static
+                $current = current($this->tokens);
+                if ($current[0] == T_VARIABLE)
+                    next($this->tokens);
+                break;
+            case T_CLASS:
+                // XXX: PHP does not allow nested classes
+                $this->traverseClass(
+                    array($token[2], $function['file']));
+                break;
+            case T_FUNCTION:
+                // PHP does not automatically nest scopes. Variables
+                // available inside the closure must be explictly defined.
+                // Therefore, there is no need to pass the current scope.
+                // However, $this is not allowed inside inline functions
+                // unless declared in the use () parameters.
+                $this->traverseFunction(
+                    array($token[2], $function['file']),
+                    array('allow_this'=>false));
+                break;
+            case T_STATIC:
+                $c = current($this->tokens);
+                // static::func() or static::$var
+                if ($c[0] == T_PAAMAYIM_NEKUDOTAYIM)
+                    break;
+            case T_GLOBAL:
+                while (list(,$token) = each($this->tokens)) {
+                    if ($token == ';')
+                        break;
+                    elseif (!is_array($token))
+                        continue;
+                    elseif ($token[0] == T_VARIABLE)
+                        $scope[$token[1]] = 1;
+                }
+                break;
+            case T_FOR:
+                // for ($i=0;...)
+                // Find first semi-colon, variables defined before it should
+                // be added to the current scope
+                while (list(,$token) = each($this->tokens)) {
+                    if ($token == ';')
+                        break;
+                    elseif (!is_array($token))
+                        continue;
+                    elseif ($token[0] == T_VARIABLE)
+                        $scope[$token[1]] = 1;
+                }
+                break;
+            case T_FOREACH:
+                // foreach ($blah as $a=>$b) -- add $a, $b to the local
+                // scope
+                $after_as = false;
+                $parens = 0;
+                // Scan for the variables defined for the scope of the
+                // foreach block
+                while (list(,$token) = each($this->tokens)) {
+                    if ($token == '(')
+                        $parens++;
+                    elseif ($token == ')' && --$parens == 0)
+                        break;
+                    elseif (!is_array($token))
+                        continue;
+                    elseif ($token[0] == T_AS)
+                        $after_as = true;
+                    elseif ($after_as && $token[0] == T_VARIABLE)
+                        // Technically, variables defined in a foreach()
+                        // block are still accessible after the completion
+                        // of the foreach block
+                        $scope[$token[1]] = 1;
+                }
+                break;
+            case T_LIST:
+                // list($a, $b) = ...
+                // Find all variables defined up to the closing parenthesis
+                while (list(,$token) = each($this->tokens)) {
+                    if ($token == ')')
+                        break;
+                    elseif (!is_array($token))
+                        continue;
+                    elseif ($token[0] == T_VARIABLE)
+                        $scope[$token[1]] = 1;
+                }
+                break;
+            case T_ISSET:
+                // isset($var)
+                // $var is allowed to be undefined and not be an error.
+                // Consume tokens until close parentheses
+                while (list(,$token) = each($this->tokens)) {
+                    if ($token == ')')
+                        break;
+                }
+                break;
+            case T_UNSET:
+                // unset($var)
+                // Var will no longer be in scope
+                while (list(,$token) = each($this->tokens)) {
+                    if ($token == ')')
+                        break;
+                    elseif (is_array($token) && $token[0] == T_VARIABLE) {
+                        // Check for unset($var[key]) -- don't unset anything
+                        // Check for unset($this->blah)
+                        $next = current($this->tokens);
+                        switch ($next[0]) {
+                        case '[':
+                        case T_OBJECT_OPERATOR:
+                            break;
+                        default:
+                            unset($scope[$token[1]]);
+                        }
+                        break;
+                    }
+                }
+                break;
+            case T_DOLLAR_OPEN_CURLY_BRACES:
+            case T_CURLY_OPEN:
+                // "{$a .. }"
+                // This screws up block detection. We will see another close
+                // brace somewhere along the way
+                $blocks++;
+                break;
+            }
+        }
+    }
+}
+?>
diff --git a/setup/test/tests/class.test.php b/setup/test/tests/class.test.php
index 5ce1297619714533c19bdfd7f2c083b4b9d255b8..de9c4f7e9da3682beaf3d244bb18778f19eda664 100644
--- a/setup/test/tests/class.test.php
+++ b/setup/test/tests/class.test.php
@@ -2,6 +2,7 @@
 
 class Test {
     var $fails = array();
+    var $warnings = array();
     var $name = "";
 
     var $third_party_paths = array(
@@ -57,7 +58,7 @@ class Test {
     }
 
     function warn($message) {
-        $this->fails[] = array(get_class($this), '', '', 'WARNING: '.$message);
+        $this->warnings[] = array(get_class($this), '', '', 'WARNING: '.$message);
         fputs(STDOUT, 'w');
     }
 
diff --git a/setup/test/tests/lib/phplint.tcl b/setup/test/tests/lib/phplint.tcl
deleted file mode 100755
index 30e10074baba6f31705c1c0b152995b33f564f66..0000000000000000000000000000000000000000
--- a/setup/test/tests/lib/phplint.tcl
+++ /dev/null
@@ -1,217 +0,0 @@
-#!/usr/bin/tclsh
-
-# Copyright (C) 2007 Salvatore Sanfilippo <antirez at gmail dot com>
-# This software is released under the GPL license version 2
-
-proc scan file {
-    set fd [open $file]
-    set infunc 0
-    set linenr 0
-    set fnre {(^\s*)((public|private|protected|static)\s*)*function(?=\s|\()\s*([^(]+)?\s*\(((\(\)|[^)])*)\)(\s*use\s*\((.*)\))?}
-    while {[gets $fd line] != -1} {
-        incr linenr
-        if {[regexp $fnre $line - ind - - - fa - - ua]} {
-            # If $infunc is true we miss the end of the last function
-            # so we analyze it now.
-            if {$infunc} {
-                analyze $file $arglist $body
-            }
-            set body {}
-            set arglist {}
-            foreach arg [split $fa ,] {
-                # remove default value
-                regsub {=.*} $arg {} arg
-                # remove optional type spec
-                regsub {^.*\s+} [string trim $arg] {} arg
-                set arg [string trim $arg " $&"]
-                lappend arglist $arg
-            }
-            # Support closure variables
-            foreach arg [split $ua ,] {
-                set arg [string trim $arg " $"]
-                lappend arglist $arg
-            }
-            set infunc 1
-        } elseif {$infunc && [regexp "^$ind\}" $line]} {
-            set infunc 0
-            analyze $file $arglist $body
-        } elseif {$infunc} {
-            lappend body $linenr [string trim $line]
-        }
-    }
-}
-
-proc analyze {file arglist body} {
-    set initialized(this) 1
-    set linton 1
-    foreach arg $arglist {
-        set initialized($arg) 1
-    }
-    # Superglobals
-    set superglobals {
-        "GLOBALS"
-        "_SESSION"
-        "_SESSION"
-        "_GET"
-        "_POST"
-        "_REQUEST"
-        "_ENV"
-        "_SERVER"
-        "_FILES"
-        "php_errormsg"
-    }
-    foreach sg $superglobals {
-        set initialized($sg) 1
-    }
-    # analyze body
-    foreach {linenr line} $body {
-        # Handle annotations
-        if {[string first {nolint} [string tolower $line]] != -1} continue
-        if {[string first {linton} [string tolower $line]] != -1} {
-            if {$linton == 1} {
-                puts "! Warning 'linton' annotation with lint already ON"
-                continue
-            }
-            set linton 1
-            puts ". $skipped lines skipped in $file from line $skipstart"
-        }
-        if {[string first {lintoff} [string tolower $line]] != -1} {
-            if {$linton == 0} {
-                puts "! Warning 'lintoff' annotation with lint already OFF"
-                continue
-            }
-            set linton 0
-            set skipped 0
-            set skipstart [expr {$linenr+1}]
-            continue
-        }
-        if {$linton == 0} {
-            incr skipped
-            continue
-        }
-        # Skip comments
-        if {[string index $line 0] eq {#}} continue
-        if {[string index $line 0] eq {/} && [string index $line 1] eq {/}} continue
-        # PHP variable regexp
-        set varre {\$[_A-Za-z]+[_A-Za-z0-9]*(\[[^\]]*\])*}
-        # Check for globals
-        set re {\s*(global|static)\s+((?:\$[^;,]+[ ,]*)+)(;|$)}
-        if {[regexp $re $line -> - g]} {
-            set g [split [string trim $g ";"] ,]
-            foreach v $g {
-                set v [string trim $v "$ "]
-                set initialized($v) 1
-            }
-        }
-        # Check for assignment via foreach ... as &$varname
-        set re {}
-        append re {foreach\s*\(.*\s+as\s+&?(} $varre {)\s*\)}
-        set l [regexp -all -inline -nocase $re $line]
-        foreach {- a -} $l {
-            set initialized([string trim $a "$ "]) 1
-        }
-        # Check for assignment via foreach ... as $key => &$val
-        set re {}
-        append re {foreach\s*\(.*\s+as\s+(} $varre {)\s*=>\s*&?(} $varre {)\s*\)}
-        set l [regexp -all -inline -nocase $re $line]
-        foreach {- a1 - a2 -} $l {
-            set initialized([string trim $a1 "$ "]) 1
-            set initialized([string trim $a2 "$ "]) 1
-        }
-        # Check for assigments in the form list($a,$b,$c) = ...
-        set re {list\s*\(([^=]*)\)\s*=}
-        set l [regexp -all -inline $re $line]
-        foreach {- vars} $l {
-            foreach v [split $vars ,] {
-                set v [string trim $v "$ "]
-                set initialized($v) 1
-            }
-        }
-        # Check for assigments via = operator
-        set re $varre
-        append re {\s*=}
-        set l [regexp -all -inline $re $line]
-        foreach {a -} $l {
-            set a [string trim $a "=$ "]
-            regsub -all {\[.*\]} $a {[]} a
-            #puts "assigmnent of $a"
-            set initialized($a) 1
-            regsub -all {\[\]} $a {} a
-            set initialized($a) 1
-        }
-        # Check for assignments via catch(Exception $e)
-        set re {}
-        append re {catch\s*\(.*\s+(} $varre {)}
-        set l [regexp -all -inline -nocase $re $line]
-        foreach {- a} $l {
-            set initialized([string trim $a "$ "]) 1
-        }
-        # Check for assignments by reference
-        #
-        # funclist format is {type funcname spos epos} where spos is the
-        # zero-based index of the first argument that can be considered
-        # an assignment, while epos is the last.
-        #
-        # name is the function name to match, and type is what
-        # to do with the args. "assignment" to consider them assigned
-        # or "ingore" to ingore them for the current line.
-        #
-        # The "ignore" is used for isset() and other functions that can
-        # deal with not initialized vars.
-        unset -nocomplain -- ignore
-        array set ignore {}
-        set funclist {
-            assignment scanf 2 100
-            assignment preg_match 2 100
-            assignment preg_match_all 2 100
-            assignment ereg 2 100
-            ignore isset 0 0
-        }
-        set cline $line
-        regsub -all {'[^']+'} $cline {''} cline
-        foreach {type name spos epos} $funclist {
-            set re {}
-            append re $name {\s*\(([^()]*)\)}
-            foreach {- fargs} [regexp -all -inline $re $cline] {
-                set argidx 0
-                foreach a [split $fargs ,] {
-                    set a [string trim $a ", $"]
-                    regsub -all {\[.*\]} $a {} a
-                    if {$argidx >= $spos && $argidx <= $epos} {
-                        if {$type eq {assignment}} {
-                            set initialized($a) 1
-                        } elseif {$type eq {ignore}} {
-                            set ignore($a) 1
-                        }
-                    }
-                    incr argidx
-                }
-            }
-        }
-
-        # Check for var accesses
-        set varsimplere {(?:::)?\$[_A-Za-z]+[_A-Za-z0-9]*}
-        set l [regexp -all -inline $varsimplere $line]
-        foreach a $l {
-            set a [string trim $a "=$ "]
-            regsub -all {\[.*\]} $a {} a
-            # Skip access to class-static variables
-            if {[string first :: $a] == 0} {
-                continue
-            }
-            #puts "access of $a"
-            if {![info exists initialized($a)] &&
-                ![info exists ignore($a)]} {
-                puts "* In $file line $linenr: access to uninitialized var '$a'"
-            }
-        }
-    }
-}
-
-proc main argv {
-    foreach file $argv {
-        scan $file
-    }
-}
-
-main $argv
diff --git a/setup/test/tests/test.unitialized.php b/setup/test/tests/test.unitialized.php
index 09bd0509e155072ccb6044429248965c2e318b36..47978fdb2fd9741bd2c4f554d527795a4927cbed 100644
--- a/setup/test/tests/test.unitialized.php
+++ b/setup/test/tests/test.unitialized.php
@@ -1,5 +1,6 @@
 <?php
 require_once "class.test.php";
+require_once "class.php_analyze.php";
 
 class UnitializedVars extends Test {
     var $name = "Access to unitialized variables";
@@ -7,16 +8,21 @@ class UnitializedVars extends Test {
     function testUnitializedUsage() {
         $scripts = $this->getAllScripts();
         $matches = array();
-        foreach (range(0, count($scripts), 40) as $start) {
-            $slice = array_slice($scripts, $start, 40);
-            ob_start();
-            # XXX: This won't run well on Windoze
-            system(dirname(__file__)."/lib/phplint.tcl ".implode(" ", $slice));
-            $lint_errors = ob_get_clean();
-            preg_match_all("/\* In (.*) line (\d+): access to uninitialized var '([^']+)'/m",
-                    $lint_errors, $matches, PREG_SET_ORDER);
-            foreach ($matches as $match)
-                $this->fail($match[1], $match[2], "'\${$match[3]}'");
+        foreach ($scripts as $s) {
+            $a = new SourceAnalyzer($s);
+            $a->parseFile();
+            foreach ($a->bugs as $bug) {
+                if ($bug['type'] == 'UNDEF_ACCESS') {
+                    list($line, $file) = $bug['line'];
+                    $this->fail($file, $line, "'{$bug['name']}'");
+                }
+                elseif ($bug['type'] == 'MAYBE_UNDEF_ACCESS') {
+                    list($line, $file) = $bug['line'];
+                    $this->warn("Possible access to NULL object @ $file : $line");
+                }
+            }
+            if (!$a->bugs)
+                $this->pass();
         }
     }
 }