What follows are the two main pieces of mod_rewrite that I ever use. I've posted these in separate places before, so this is mostly just to aggregate them in one place, as well as to explain how I make sure all URLs on my site are "clean".
First, these rules pass any request for a file that doesn't exist through the "dispatcher", a PHP script which can then do whatever it wants to. It serves as a Front controller (in that article's terminology, Apache acts as the "controller" while dispatcher.php acts as the "dispatcher"). Importantly, note that with the second line commented out, like I have it, this also bypasses directory handling (mod_dir) which means that any index.php, index.html, etc. will never be called. I prefer it this way mainly because I don't like mod_dir sticking trailing slashes on the end of any my URLs. I have a strict policy that no URL on my site can end with a slash (try appending a slash to a URL on my site, I dare you). The way I do it, no URLs have extensions (except images and things that I want to be served directly by Apache) so everything can look like a directory anyway.
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
#RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /dispatcher.php [L]
All of the mod_rewrite directives I list here I have in my .htaccess file in my document root. Note that the slash before dispatcher.php is important, as an analysis of mod_rewrite logs shows that while it would work without the leading slash, having the leading slash makes the translation take fewer steps (which is presumably more efficient).
The way I handle my content is that I have a special "content" directory outside of my document root and my dispatcher parses the URL and serves up what you want if it exists. This way I avoid cluttering up my document root. I don't personally use the following rewrite rules because of this, and because I serve things through the front controller rather than directly, but if you use the following rules, any .php file in your document root will be able to be served without an extension.
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule . %{REQUEST_FILENAME}.php [L]
Of course, this has to go before the above directives, otherwise it won't be run because dispatcher will get things first. To prevent the files from being accessed with the .php extension, you may want to implement some logic, possibly using auto_prepend_file, to do a permanent redirect from the .php version to the sans-.php version. Because the regular expressions in mod_rewrite don't support non-greedy matching, I don't think there's any way do that redirect in mod_rewrite itself, you need to use PHP for that. It can be as simple as something like:
<?php
if(substr($filename, -4) == '.php')
setHttpLocation(substr($filename,0,-4)); #take off the .php
?>
In fact, that's taken almost directly from my dispatcher. setHttpLocation() is straightforward -- leaving it in there makes it work as good pseudocode.
Then, to handle subdirectories in this scheme, you can use subdir.php to represent the subdirectory root (instead of having something like subdir/index.php), and then subdir/whatever.php to handle subdir/whatever).
The other way you can make clean URLs with PHP is by using the following directive in your .htaccess file:
DefaultType application/x-httpd-php
That will make any file not recognized by Apache, including files without extensions, be served as PHP, but this creates problems if you want to have subdirectories since you can't have a file and a directory with the same name.
Update (Jul 9, 04): Note that if you use the dispatcher.php mod_rewrite rules above, you should also add dispatcher.php to your DirectoryIndex setting.
Update (Jul 13, 04): Also see this. You'll probably want to change one of the above lines to "RewriteRule . %{REQUEST_FILENAME}.php%{PATH_INFO} [L]".
Thank you! For ages I was wondering why my test page (iamsparticus.co.uk/bilfred) was not working sans extension, but it's because I set it up as a subdomain to test some stuff ages ago. Woo!