Free Trial

Safari Books Online is a digital library providing on-demand subscription access to thousands of learning resources.


  • Create BookmarkCreate Bookmark
  • Create Note or TagCreate Note or Tag
  • DownloadDownload
  • PrintPrint
Share this Page URL
Help

4. Connecting PHP to MySQL > Cleaning Up Your Code with Multiple Files

Cleaning Up Your Code with Multiple Files

Even if you don’t realize it yet, there’s something problematic about your connect.php script. Look at the first few MySQL calls you make:

<?php
  mysql_connect("your.database.host",
                "your-username", "your-password")
    or die("<p>Error connecting to database: " .
           mysql_error() . "</p>");

  echo "<p>Connected to MySQL!</p>";

  mysql_select_db("your-database-name")
    or die("<p>Error selecting the database bmclaugh: " .
           mysql_error() . "</p>");

  echo "<p>Connected to MySQL, using database bmclaugh.</p>";

  // And so on...
?>

You’re manually typing your database host, your username, your password, and your database name into your script. Now suppose you have 10 scripts and you’re typing that 10 times. The chance of a typo is pretty high.

Not only that, what happens when you change your password? Or you upgrade to a better hosting plan to handle all the web traffic your apps are generating, and you need to change your database host? You’ve got to track down every place you put that information, in every PHP script. That’s a nightmare, and keeps you from actually writing new code and making more cash. Not good.

You need a way to abstract out those pieces of information. Abstraction is a programming term that means hiding the implementation, the way something (like a password) works, from the programs that uses it. You basically have a symbol, or a name, and that name refers to something else with a lot more detail. And even if that detail changes, the name still points to the right thing.

It’s like saying “Leigh,” and meaning my wife, without having to say, “that hot 34-year old woman with short blond hair and great legs.” And the beauty of “Leigh” is that every birthday, you can keep saying, “Leigh,” instead of changing your description.

Replacing Hand-Typed Values with Variables

So suppose you want your code to look more like this (actually, you really do want it to look more like this):

<?php
  mysql_connect($database_host, $username, $password)
    or die("<p>Error connecting to database: " .
           mysql_error() . "</p>");

  echo "<p>Connected to MySQL!</p>";

  mysql_select_db($database_name)
    or die("<p>Error selecting the database bmclaugh: " .
           mysql_error() . "</p>");

  echo "<p>Connected to MySQL, using database bmclaugh.</p>";

  // And so on...
?>

All you’re doing is writing something that looks a bit like a variable in place of hand-typing the username or database name. Now you can define those variables up above your connection code:

<?php
  $database_host = "your.database.host";
  $username = "your-username";
  $password = "your-password";
  $database_name = "your-database-name";

  // Database connection code
?>

But is this really that much better? Not yet; you’ve still got these same values hand-typed into your script. You want to stick the values in a file so no human has to type them. Read on.

Abstracting Important Values into a Separate File

Your goal is to get these values out of connect.php, into some place that all your PHP scripts can access them with no typing from you. Open up a new file, and call it app_config.php. Now drop your variables into this new file:

<?php
// Database connection constants
$database_host = "your.database.host";
$username = "your-username";
$password = "your-password";
$database_name = "your-database-name";

?>

Note

Be sure and save app_config.php somewhere that makes sense for all your application’s scripts to access it. In this book’s examples, app_config.php is in the root of the site, under scripts/. So if you’re in the ch04/scripts/ directory, you’d access this file at ../../scripts/app_config.php, or [site_root]/scripts/app_config.php. You can save the file wherever you want, as long as you get the path right in your PHP scripts that reference it.

When you move to a production version of your application, you probably want to place this file outside of the site root. That way, web users can’t simply type the path to your configuration script and get all your passwords. Alternatively, you could add security to this directory, although simply getting it out of the web-serving directories altogether is usually easiest.

Now, you can have all your different PHP scripts use these shared variables. Change a variable here in app_config.php, and that change affects all your PHP scripts that use these shared variables.

But how do you actually access these variables? Go back to connect.php, and remove where you defined these variables yourself. If you try and access connect.php through connect.html now, though, you’ll get a nasty error, as shown in see Figure 4-6.

You defined your variables in app_config. php, but connect.php doesn’t know this. You need to tell your connection script that it shouldn’t run until it loads app_config.php. Then things will behave, because the variables connect.php uses will be set properly.

Figure 4-6. You defined your variables in app_config. php, but connect.php doesn’t know this. You need to tell your connection script that it shouldn’t run until it loads app_config.php. Then things will behave, because the variables connect.php uses will be set properly.

The error occurs because connect.php now has no idea what $username or $password refers to. You need to inform PHP that before it tries to do anything in connect.php, it’s required to load app_config.php. And that’s (almost) exactly what you type in your script:

<?php

  require '../../scripts/app_config.php';

  // Database connection code
?>

Now, PHP loads the file ../../scripts/app_config.php before it runs your mysql_connect function. In effect, require says, “Hey PHP, if you can’t load the file I’m giving, then throw a nasty error, because nothing else is going to work.”

Warning

Make sure the path and filename you give require matches where you actually put app_config.php, or you’ll see the error that require produces up close and personal.

Try and run your connection script again, and you should see your table listing, which means things are working well again.

UNDER THE HOOD: Require or Include?

There’s another command in PHP that’s very similar to require: include. include does exactly what require does in terms of telling PHP to load another file. The difference is that if that file can’t be loaded, include just issues a warning and lets PHP keep running the later commands in your script. In other words, require completely shuts things down, but include lets your script keep going.

But here’s the thing. Are you really going to bother including a file if you don’t need that file? In most cases, probably not. And you’re including that file because you need it; you require that file to run. So in almost every situation, you should use require to grab another file, not include. If something goes wrong, you want to know about it. You don’t want the rest of your code running, because it’s probably just going to error out anyway.

Variables Vary, But Constants Stay Constant

There’s just one more nagging little problem with your code: you’re still using variables for your username and password, along with the database host and database name. And what’s a variable? Something that varies or changes. Accordingly, PHP happily lets you write the following code in connect.php:

mysql_connect($database_host, $username, $password)
  or die("<p>Error connecting to database: " . mysql_error() . "</p>");

// This is allowed, but some bad mojo
$password = "hijinks";

So what happens when some other script—which also requires app_config.php—tries to connect with mysql_connect? It’s going to use $password, but now $password isn’t correct anymore. It’s set to “hijinks,” and chaos will ensue.

What you really want is for those values in app_config.php to be constant, and never change. You can do this with the special define function. Open up app_config.php and change your code:

<?php
// Database connection constants
define("DATABASE_HOST", "your.database.host");
define("DATABASE_USERNAME", "your-username");
define("DATABASE_PASSWORD", "your-password");
define("DATABASE_NAME", "your-database-name");
?>

You define the name of a constant and the value for that constant, and PHP creates a new constant. That way, you can type DATABASE_HOST into your code, and PHP really sees “your.database.host”. Perfect! And since this is a constant, it can’t be changed anywhere along the line.

Constants are typed in all-uppercase letters. Caps aren’t required, but it’s another one of those “speak like a PHP programmer” things. You want constants to look different from variables, and using all uppercase names is one way to do that. Constants also don’t have the $ before their name, which is yet another way to differentiate a constant from a variable.

Now you need to make some quick changes to connect.php to use these new capitalized names of constants:

<?php
  require '../../scripts/app_config.php';

  mysql_connect(DATABASE_HOST, DATABASE_USERNAME, DATABASE_PASSWORD)
    or die("<p>Error connecting to database: " .
           mysql_error() . "</p>");

  echo "<p>Connected to MySQL!</p>";

  mysql_select_db(DATABASE_NAME)
    or die("<p>Error selecting the database " . DATABASE_NAME .
           mysql_error() . "</p>");

  echo "<p>Connected to MySQL, using database " . DATABASE_NAME . "</p>";

  // SQL query-running goodness proceeds...
?>

Warning

You can’t use the { } inside your quotes to print constants. It’s only when you surround a variable (which starts with $) with { } that PHP prints the value of that variable. Instead, use the normal string concatenation approach where you end your string and add the constants using the dot (.), as discussed on Combining Text.

Try connect.php again. You should get a perfectly good list of table names. But this time, you’ve got constants for your important information, safely tucked away in a file separated out of connect.php.

Note

It’s also a good idea to add some additional security to app_config.php, and any other scripts that contain special values like passwords. You can set the permissions on the file to be more restrictive, or move the file to some place your PHP script can access, but your web users can’t. Ask your web or server admin for help if you’re not sure how to do that.

DESIGN TIME: Start Small, Add Small, Finish Small

You may be wondering why you couldn’t have just started with app_config.php, and the completed, working version of connect.php. Or, at a minimum, you could have just dropped all the database connection code into connect.php at once, and then done the printing code all at once. Isn’t that how real developers write code?

Well, yes and no. Lots of developers do write code like that. They type 10 or 20 or 50 lines of code into their script, and then try it out. Lots of things will break, because developers type too fast and make mistakes. But then they’ll fix each problem, one by one by one. And for lots of developers, that’s just fine.

But here’s the thing: that’s not a very efficient way of working. On top of that, you’re usually focused on the last step (like printing out the tables), and so you may not spend much time figuring out the best way to handle the in-between steps. You might not use { } to simplify the statement that prints $row[0], or you may skip a die because you’re thinking about HTML output, not handling the case where the database password isn’t right.

The best developers work on really, really small chunks of code at a time. They test that code, and then they move on to something else. In fact—and this goes a bit beyond this book, but it’s still important—a lot of really elite developers actually write tests before they write anything else. They write those tests, and the tests obviously fail, because they haven’t written any code. Then they write just enough code to pass their test, and then they write another test.

This method may not make much sense at first. Why write tests for code that doesn’t exist? Here’s what’s really nuts: often, this approach results in more test code than actual application code! It’s a lot of work, and it’s all based on the idea that you should write just enough code to get one thing working at a time.

But here’s the big reveal, and why these elite developers are elite: this test-first approach results in better code. Working small, from start to finish, means you’re focusing on one thing, and doing that one thing really well. You aren’t rushing on to something else. And that means what you’re working on is solid and works. This approach does take more time in the beginning, but it results in rock-solid code that breaks a lot less often.

So take your time, and work small. Your code will be better, and your customers will love you because your code is still running while they’re on the phone trying to get help with a broken app from “the other guys.”