9

I'm currently working on a very large project, and am under a lot of pressure to finish it soon, and I'm having a serious problem. The programmer who wrote this last defined variables in a very odd way - the config variables aren't all in the same file, they're spread out across the entire project of over 500 files and 100k+ lines of code, and I'm having a hell of a time figuring out where a certain variable is, so I can fix an issue.
Is there a way to track this variable down? I believe he's using SMARTY (Which I can not stand, due to issues like this), and the variable is a template variable. I'm fairly sure that the variable I'm looking for was initially defined as a PHP variable, then that variable is passed into SMARTY, so I'd like to track down the PHP one, however if that's impossible - how can I track down where he defined the variable for SMARTY?

P.S. I'm in Vista, and don't have ssh access to the server, so 'grep' is out of the question.

Jon
  • 305
  • 3
  • 20
  • 45
  • 1
    +1 for not liking Smarty. While not using them myself, I think php-debugger and xdebug can both backtrack variables/contents in outer scopes or all existing variables at least. Anyway, I've lit a candle of compassion for your Vista and debugging situation. – mario Jun 04 '10 at 04:37

6 Answers6

9

Brute force way, because sometimes smarty variables are not directly assigned, but their names can be stored in variables, concatenated from many strings or be result of some functions, that makes it impossible to find in files by simply searching / greping.

Firstly, write your own function to print readable backtrace, ie:

function print_backtrace()
{
    $backtrace = debug_backtrace(FALSE);
    foreach($backtrace as $trace)
        echo "{$trace['file']} :: {$trace['line']}<br>";
}

Open main smarty file (Smarty.class.php by default) and around line 580 there is function called assign. Modify it to watch for desired variable name:

function assign($tpl_var, $value = null)
{
    if($tpl_var == 'FOOBAR') /* Searching for FOOBAR */
    {
        print_backtrace();
        exit;
    }

The same modification may be required for second function - assign_by_ref. Now after running script you should have output like that:

D:\www\test_proj\libs\smarty\Smarty.class.php :: 584
D:\www\test_proj\classes.php :: 11
D:\www\test_proj\classes.php :: 6
D:\www\test_proj\functions.php :: 7
D:\www\test_proj\index.php :: 100

Second line points to the place where variable was first assigned.

dev-null-dweller
  • 29,274
  • 3
  • 65
  • 85
  • Thanks, this is a great idea - I'm definitely saving this code for future debugging, however I ended up just using grep as suggested below. – Jon Jun 14 '10 at 16:26
  • This may work great with SMARTY, but it doesn't appear to state where a particular variable in a file is initially defined in just PHP. I think debug_backtrace and/or Reflection can find that, but I don't see the way referenced here. – SteveExdia Jan 20 '22 at 19:59
7

This sort of thing is the #1 reason I install Cygwin on all my windows machines.

grep myvariablename `find project_dir -name "*.php"`

I can't imagine programming without a working grep.

Nathan
  • 3,842
  • 1
  • 26
  • 31
  • 1
    Holy smokes that looks awesome. Installing now from CPAN everywhere. – Nathan Jun 04 '10 at 22:05
  • Hey, I've been using ack for a couple weeks now and I love it. Thanks again, Charles! – Nathan Jun 21 '10 at 18:59
  • @AlxVallejo it is difficult in spaghetti PHP but you could try looking for all assignment statements with something like `ack '^\s*\$image\s*='` – Nathan Mar 27 '14 at 18:21
  • Hi @Nathan, I'm about to install Cygwin on **Win8**, but I don't know which is the package I must install to achieve this. Can you which is te one (or more)? – Cliff Burton Apr 18 '15 at 12:59
  • @CliffBurton that's one of the confusing things about Cygwin... but there is a `grep` package. Also compare *ag the silver searcher*. Good luck. – Nathan May 11 '15 at 19:15
  • Thanks for the hint to `ack`. – peter_the_oak Jan 26 '17 at 13:40
6

There is an interesting further option, ugly like hell but helpful if you are really lost.

If you would like to know where THE_NAME was defined, write lines like these on a place you are sure is run first:

error_reporting(E_ALL);
define('THE_NAME', 'Chuck Norris');

If later PHP will run the definition you are looking for, it will write a notice like this:

Notice: Constant THE_NAME already defined 
in /home/there/can-rip-a-page-out-of-facebook.com/SomeConfiguration.php on line 89 

Then you know that the definition you are looking for is in the file SomeConfiguration.php on line 89.

To have this working, you must consider

  • if there are HTTP forwards in the framework on the way to the code you set in
  • if there are further commands setting the PHP error reporting mode

So sometimes it helps to add some exit('here') in order not to blur the output. Maybe you have to narrow down a bit or you have to set error_reporting earlier, but you'll find it.

peter_the_oak
  • 3,529
  • 3
  • 23
  • 37
2

It's not a perfect solution, but I find agent ransack useful for searching large directories and files. Might help you narrow things down. The search results will allow you to read the exact line it finds a match on in the result pane.

Steerpike
  • 17,163
  • 8
  • 39
  • 53
2

If you use the netbeans editor just "right click" -> "go to Definition"

Or ctrl + click on the variable.

If the editor can't figure it out, you could fallback to the "Find in files" option.

Bob Fanger
  • 28,949
  • 7
  • 62
  • 78
1

Just use one of the available PHP IDEs (or a simple text editor like Notepad++ if you're really desperate) and search for the name of the variable in all source files (most PHP IDEs also support finding where functions/vars were defined and allow you to jump to the relevant piece of code). Though it seems weird that you don't know what piece of code calls the template (whether it's Smarty or anything else doesn't really matter). You should be able to drill down in the code starting from the URI (using any IDE which supports debugging), because that way you're bound to see where said variable is defined.

wimvds
  • 12,790
  • 2
  • 41
  • 42