Have I gone too far in factoring out repeated code in this example?
I think what you did was a good thing. I also think you could combine the first 2 functions as well. 

Something like this: 

private function _add_item($path, $type, $where = self::ADD_LAST) {
    $script = "&lt;script src='$path'&gt;&lt;/script&gt;\n";
    $css = "&lt;link rel='stylesheet' href='$path'&gt;\n";

    if ($type == 'script') {
        $html = $script; 
    }
    elseif ($type == 'css') {
        $html = $css;
    }

    $this-&gt;_add_external($type, $html, $where);
}


Or this: 

private function _add_item($path, $type, $where = self::ADD_LAST) {
    $script = "&lt;script src='$path'&gt;&lt;/script&gt;\n";
    $css = "&lt;link rel='stylesheet' href='$path'&gt;\n";

    switch($type) {
        case 'script':
            $html = $script; 
            break;
        case 'type':
            $html = $css;
            break;
    }

    $this-&gt;_add_external($type, $html, $where);
}


Or this (My favorite): 

private function _add_item($path, $type, $where = self::ADD_LAST) {
    $array['script'] = "&lt;script src='$path'&gt;&lt;/script&gt;\n";
    $array['css'] = "&lt;link rel='stylesheet' href='$path'&gt;\n";

    $html = $array[$type]; 

    $this-&gt;_add_external($type, $html, $where);
}


EDIT:  

And I think this would work too, an all in one solution:  

private function _add_item_external($path, $type, $where = self::ADD_LAST) {
    $array['script'] = "&lt;script src='$path'&gt;&lt;/script&gt;\n";
    $array['css'] = "&lt;link rel='stylesheet' href='$path'&gt;\n";

    switch($where) {
        case self::ADD_LAST:
            array_push($this-&gt;_data[$type], $array[$type]);
            break;
        case self::ADD_FIRST:
            array_unshift($this-&gt;_data[$type], $array[$type]);
            break;
    }
}