This is because $2 does not exist.. The way preg works, is that every set of capturing brackets (from left to right), stores what it matches starting with variable $1, $2, etc... since you only have one set of capturing brackets ([(.*?)]), the value it matches is stored into $1, so you need to use that instead.. I suspect another issue might be that you have an array $db_row with a key named $2, and that preg thinks you are trying to insert 'the second captured value' in place of $2.. but obviously, there is no second capture.. (I'll get to this in a code sample at the bottom).
Also, note that both [name_field] and [roll_field] will be replaced with whatever value you are looking to replace it with in your current pattern, as preg_replace will find all instances of [....] and replace that. If you need to target just the first one by example, explicitly point that out in the preg pattern.. so for example:
$string = 'my/name/[name_field]/roll/[roll_field]';
$db_row['$2'] = 'whatever!';
$finalstring = preg_replace('#\[name_field\]#', $db_row["$2"], $string);
Output (when echo'ing $finalstring):
my/name/whatever!/roll/[roll_field]
Is that along the lines of what you are looking for?
EDIT - Obviously, if you do want to replace all instances of [...], you can use: #[[]]+]# as your pattern instead.