Build a PHP Paycheck Calculator

Learn PHP fundamentals by building a paycheck calculator from scratch.

Introduction

30 Second Summary

Everyone has received a paycheck and wondered how the final number was calculated. Taxes, overtime, deductions. What if you could write code that breaks down every piece of that math yourself?

In this project, you will build a PHP paycheck calculator that computes gross pay, tax deductions, overtime eligibility, and net pay. The script runs directly in your browser through XAMPP.

What You'll Build

A PHP script served through XAMPP's Apache server that uses variables, constants, data types, and operators to calculate and display a full paycheck breakdown in your browser.

By the end of this project, you'll have:

  • A working PHP paycheck calculator that runs in your browser via XAMPP's local server.
  • Hands-on experience with PHP variables, constants, and all core data types including string, int, float, bool, null, and array.
  • Real paycheck calculations using arithmetic, comparison, and logical operators to determine overtime, tax, and bonus eligibility.
  • Secret Mission: Add a second employee and build a comparison table using associative arrays and the ternary operator.

Are there any prerequisites?

A basic understanding of HTML is helpful so you recognise the page-structure tags the calculator outputs. No prior PHP or backend experience is required.

Set Up Your First PHP Script

Before you can write any PHP logic, you need a local web server that can execute PHP files.

XAMPP bundles Apache and PHP together, so starting Apache in XAMPP gives you a working PHP server on your own machine. In this step, you will create a project folder, write your first PHP script, and confirm it runs in the browser.

In this step, get ready to:
  • Start Apache in XAMPP and create your project folder.
  • Write and test your first PHP script in the browser.
  • Wrap your PHP output in a proper HTML page structure.
Start Apache and create your project folder

Apache is the web server that processes PHP files and sends the result to your browser. XAMPP gives you a one-click way to start it.

  • Press the Windows key to open your search bar.
  • Type XAMPP and press Enter to open the XAMPP Control Panel.
  • Click the Start button next to Apache.

The Apache row turns green when the server is running successfully.

Apache won't start?

Another program may already be using port 80. Close Skype, IIS, or any other web server, then try clicking Start again.

help me start Apache in XAMPP

Now you need to create a project folder inside XAMPP's web root. Any folder placed in htdocs becomes accessible through your browser at http://localhost/.

  • Open File Explorer and navigate to C:\xampp\htdocs.
  • Right-click in the folder, select New, then Folder.
  • Name the new folder paycheck.

Next, open this folder in VS Code so you can create your PHP file.

  • Press the Windows key, type VS Code, and press Enter to open it.
  • Click File in the top menu bar.
  • Click Open Folder.
  • Navigate to C:\xampp\htdocs\paycheck and click Select Folder.

You should see the paycheck folder name in the VS Code Explorer sidebar on the left.

  • In the Explorer sidebar, hover over the PAYCHECK heading and click the New File icon (a page with a plus sign).
  • Type index.php and press Enter.

VS Code opens the empty index.php file in the editor pane. This is where you will write all your PHP code.

Every PHP file starts with an opening <?php tag that tells the server to start interpreting PHP. The echo command outputs text to the browser.

  • Write your first PHP code in index.php by copying the following:
<?php
echo 'Paycheck Calculator Starting...';
?>

What does this code do?

The <?php tag tells Apache to process everything that follows as PHP code. The ?> tag marks the end of the PHP block.

The echo statement sends text directly to the browser. The line ends with a semicolon, which is required to terminate every PHP statement.

  • Save index.php by pressing Ctrl+S.
  • Open your browser (Chrome or Edge) and visit http://localhost/paycheck/index.php.
  • You should see the text "Paycheck Calculator Starting..." displayed on the page.

Seeing a blank page or an error?

Make sure Apache is still running in the XAMPP Control Panel (the Apache row should be green).

Double-check that your file is saved as index.php (not index.php.txt) and sits inside C:\xampp\htdocs\paycheck.

help me troubleshoot my PHP file not loading in the browser

Verify PHP is running with phpinfo()

PHP includes a built-in function called phpinfo() that displays a full report of your PHP installation. This is a quick way to confirm PHP is truly processing your file (not just serving it as plain text).

  • In index.php, add a new line below your echo statement so the file looks like this:
<?php
echo 'Paycheck Calculator Starting...';
phpinfo();
?>
  • Save the file and refresh your browser at http://localhost/paycheck/index.php.

You should see your "Paycheck Calculator Starting..." text at the top, followed by a large purple table showing your PHP version, loaded modules, and server configuration.

What is the phpinfo() page?

This page shows every detail about your PHP installation, including the version number, active extensions, and server settings. It is a diagnostic tool for development only.

Now that you have confirmed PHP is active, remove the diagnostic line. You do not need it for the rest of the project.

  • In index.php, delete the phpinfo(); line.
  • Save the file. Your code should be back to just the echo statement between the PHP tags.
Add an HTML wrapper around your PHP output

Right now your page outputs raw text with no HTML structure. Browsers need a proper HTML document to render content correctly, set the page title, and apply styling later.

  • Replace the entire contents of index.php with the following code:
<!DOCTYPE html>
<html>
<head>
    <title>Paycheck Calculator</title>
</head>
<body>
<?php
echo 'Paycheck Calculator Starting...';
?>
</body>
</html>

What does this code do?

The <!DOCTYPE html> declaration tells the browser this is an HTML5 document. The <title> tag sets what appears in the browser tab.

Your PHP block sits inside the <body> tags. When Apache encounters the <?php tag, it executes the PHP code and injects the output directly into the HTML that gets sent to the browser.

  • Save index.php and refresh your browser.
  • You should still see "Paycheck Calculator Starting..." on the page. Check the browser tab title. It should now display "Paycheck Calculator" instead of the URL.

Tab title still showing the URL?

Make sure the <title>Paycheck Calculator</title> line is inside the <head> section, not inside <body>. Also confirm you have saved the file after making changes.

help me fix my HTML structure in index.php

✔️ Awesome, I've got everything!

Great. Double check you have saved your file before moving on.

ⓧ I'd like to double check the full code

Here is the complete index.php file at this point:

<!DOCTYPE html>
<html>
<head>
    <title>Paycheck Calculator</title>
</head>
<body>
<?php
echo 'Paycheck Calculator Starting...';
?>
</body>
</html>

Your PHP environment is ready and your file renders as a proper web page. Next up, you will declare variables and explore PHP's data types to start building the paycheck logic.

Declare Variables and Explore Data Types

A paycheck calculator needs data to work with. Employee names, hourly rates, hours worked, employment status. In PHP, every piece of data lives inside a variable.

In this step, you will declare variables with different data types and use var_dump() to inspect exactly what PHP stores. You will also style the page so your output is easy to read as the project grows.

In this step, get ready to:
  • Declare PHP variables for employee data using five core data types.
  • Experiment with PHP's dynamic type system to understand strings vs numbers.
  • Create an array and format all output using string concatenation.
Declare employee variables and inspect them with var_dump

Every PHP variable starts with a $ sign. Variable names are case-sensitive, and PHP does not require you to declare types in advance.

  • In VS Code, replace the entire contents of index.php with the following code:
<!DOCTYPE html>
<html>
<head>
    <title>Paycheck Calculator</title>
    <style>
        body { font-family: Arial, sans-serif; margin: 40px; background: #f5f5f5; }
        h1 { color: #2c3e50; }
        h2 { color: #34495e; margin-top: 30px; }
        .section { background: white; padding: 20px; margin: 20px 0; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
        .result { color: #27ae60; font-weight: bold; }
        .label { color: #7f8c8d; }
        code { background: #ecf0f1; padding: 2px 6px; border-radius: 3px; }
    </style>
</head>
<body>

<h1>Paycheck Calculator</h1>

<?php
// ============================================
// STEP 2: VARIABLES AND DATA TYPES
// ============================================

echo '<div class="section">';
echo '<h2>Step 2: Variables and Data Types</h2>';

// Declaring variables with different data types
$employeeName = "Alice Johnson";
$hourlyRate = 25.50;
$hoursWorked = 45;
$isFullTime = true;
$middleName = null;

// Displaying variables with var_dump to see types
echo '<p class="label">var_dump of each variable:</p>';
echo '<pre>';
echo '$employeeName: '; var_dump($employeeName);
echo '$hourlyRate: '; var_dump($hourlyRate);
echo '$hoursWorked: '; var_dump($hoursWorked);
echo '$isFullTime: '; var_dump($isFullTime);
echo '$middleName: '; var_dump($middleName);
echo '</pre>';

echo '</div>';
?>

</body>
</html>

What does this code do?

The HTML and CSS at the top create a styled page so your PHP output is readable as you add more sections.

  • $employeeName is a string (text wrapped in quotes).
  • $hourlyRate is a float (a decimal number like 25.50).
  • $hoursWorked is an integer (a whole number with no decimal).
  • $isFullTime is a boolean (either true or false).
  • $middleName is null (intentionally empty, no value at all).
  • var_dump() prints both the type and value of each variable, so you can see exactly what PHP is storing.
  • Save index.php.
  • Refresh your browser at http://localhost/paycheck/index.php. You should see a styled white card with the heading "Step 2: Variables and Data Types" and a block of var_dump output showing each variable's type and value.

Don't see styled output?

  • Make sure you replaced ALL the content of index.php. If any of the old HTML structure remains outside the new code, the page may render incorrectly.
  • Check that Apache is still running in the XAMPP Control Panel. If it stopped, click Start next to Apache.
  • If you see a blank page, check for missing semicolons or unclosed quotes in the PHP block. PHP stops executing when it hits a syntax error.

Help me debug why my PHP variables aren't displaying in the browser.

Experiment with PHP's type system

PHP decides a variable's type based on how you write the value. Quotes make a string. No quotes make a number. This is called dynamic typing. You do not declare types in advance.

  • In index.php, find the closing </pre> line (after the last var_dump call). Add the following code directly below it:
// Demonstrating type difference: string vs integer
$hoursAsString = "40";
echo '<p class="label">Type difference demo:</p>';
echo '<pre>';
echo '"40" as string: '; var_dump($hoursAsString);
echo '40 as integer: '; var_dump($hoursWorked);
echo '</pre>';

What's happening here?

$hoursAsString = "40" stores the text "40" as a string because it is wrapped in quotes. Even though it looks like a number, PHP treats it as text.

$hoursWorked (which you set to 45 earlier without quotes) is stored as an integer. The var_dump() output makes this difference visible.

  • Save index.php and refresh your browser.
  • You should see a new "Type difference demo" section showing string(2) "40" for the string version and int(45) for the integer.

Seeing a syntax error?

  • Check that you placed the new code BELOW the existing echo '</pre>' line, not inside the existing pre block.
  • Make sure every echo statement ends with a semicolon.

Help me fix a PHP syntax error in my type demo code.

Create an array and format output with concatenation

PHP also has an array data type for storing multiple values in one variable. You will also learn to build readable output using PHP's string concatenation operator (the . dot).

  • In index.php, find the second echo '</pre>'; line (the one you just added in the type demo). Add the following code directly below it:
// Array data type
$deductions = ["tax", "insurance", "retirement"];
echo '<p class="label">Array variable:</p>';
echo '<pre>';
var_dump($deductions);
echo '</pre>';

// Readable output with concatenation
echo '<p class="label">Formatted output using concatenation (.):</p>';
echo '<p>Employee: <span class="result">' . $employeeName . '</span></p>';
echo '<p>Hourly Rate: <span class="result">$' . $hourlyRate . '</span></p>';
echo '<p>Hours Worked: <span class="result">' . $hoursWorked . '</span></p>';
echo '<p>Full Time: <span class="result">' . ($isFullTime ? 'Yes' : 'No') . '</span></p>';
echo '<p>Middle Name: <span class="result">' . ($middleName ?? 'Not set (null)') . '</span></p>';

What does this code do?

  • $deductions stores three string values in a single array variable. PHP arrays can hold any mix of types.
  • The . operator joins strings together. In JavaScript you would use + for this. In PHP, the dot is for concatenation and + is only for math.
  • The ?? is the null coalescing operator. It returns the left side if it is not null, otherwise it returns the right side. Perfect for showing a fallback value when $middleName is null.
  • Save index.php and refresh your browser.
  • You should see the array structure printed by var_dump() (showing 3 elements with their indices), followed by a formatted section listing each employee value with green text.

Output looks broken or shows raw HTML?

  • If you see raw HTML tags printed as text, check that your PHP opening tag is still intact. The browser only processes PHP inside the server.
  • Watch the quotes carefully. Each echo line uses single quotes for the HTML string. The dot operator joins variable values into the string.
  • Make sure you have the closing echo '</div>' and the closing PHP tag at the end of the file.

Help me fix my PHP concatenation output.

✔️ Awesome, I've got everything!

Great. Double check you have saved your file before moving on.

ⓧ I'd like to double check the full code

Here is the complete index.php at this point. Compare it to yours and fix any differences.

<!DOCTYPE html>
<html>
<head>
    <title>Paycheck Calculator</title>
    <style>
        body { font-family: Arial, sans-serif; margin: 40px; background: #f5f5f5; }
        h1 { color: #2c3e50; }
        h2 { color: #34495e; margin-top: 30px; }
        .section { background: white; padding: 20px; margin: 20px 0; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
        .result { color: #27ae60; font-weight: bold; }
        .label { color: #7f8c8d; }
        code { background: #ecf0f1; padding: 2px 6px; border-radius: 3px; }
    </style>
</head>
<body>

<h1>Paycheck Calculator</h1>

<?php
// ============================================
// STEP 2: VARIABLES AND DATA TYPES
// ============================================

echo '<div class="section">';
echo '<h2>Step 2: Variables and Data Types</h2>';

$employeeName = "Alice Johnson";
$hourlyRate = 25.50;
$hoursWorked = 45;
$isFullTime = true;
$middleName = null;

echo '<p class="label">var_dump of each variable:</p>';
echo '<pre>';
echo '$employeeName: '; var_dump($employeeName);
echo '$hourlyRate: '; var_dump($hourlyRate);
echo '$hoursWorked: '; var_dump($hoursWorked);
echo '$isFullTime: '; var_dump($isFullTime);
echo '$middleName: '; var_dump($middleName);
echo '</pre>';

$hoursAsString = "40";
echo '<p class="label">Type difference demo:</p>';
echo '<pre>';
echo '"40" as string: '; var_dump($hoursAsString);
echo '40 as integer: '; var_dump($hoursWorked);
echo '</pre>';

$deductions = ["tax", "insurance", "retirement"];
echo '<p class="label">Array variable:</p>';
echo '<pre>';
var_dump($deductions);
echo '</pre>';

echo '<p class="label">Formatted output using concatenation (.):</p>';
echo '<p>Employee: <span class="result">' . $employeeName . '</span></p>';
echo '<p>Hourly Rate: <span class="result">$' . $hourlyRate . '</span></p>';
echo '<p>Hours Worked: <span class="result">' . $hoursWorked . '</span></p>';
echo '<p>Full Time: <span class="result">' . ($isFullTime ? 'Yes' : 'No') . '</span></p>';
echo '<p>Middle Name: <span class="result">' . ($middleName ?? 'Not set (null)') . '</span></p>';

echo '</div>';
?>

</body>
</html>

You now have five different data types stored in PHP variables and a clear picture of how PHP reports each one. Next up, you will define constants for values that never change and use arithmetic operators to calculate the actual paycheck.

Define Constants and Use Arithmetic Operators

In the last step, you declared variables and explored PHP's type system. Now you have employee data stored and ready for calculations.

A real paycheck has fixed rules that never change. The tax rate is always 22%. The overtime multiplier is always 1.5x. PHP has a dedicated feature for values like these: constants. In this step, you will define constants and then use arithmetic operators to calculate gross pay, taxes, and net pay.

In this step, get ready to:
  • Define constants for fixed paycheck values using define() and const.
  • Calculate gross pay, tax, and net pay using arithmetic operators.
  • Explore modulo and operator precedence with real examples.
Define constants for your paycheck rules

Some values in a paycheck calculation should never change. The tax rate is set by law. The overtime multiplier is fixed at time-and-a-half. PHP constants lock these values down so no code can accidentally change them later.

  • In index.php, find the closing echo '</div>'; line from Step 2 (just above the ?> tag).
  • Add the following code below that line to start a new section and define your constants:
// ============================================
// STEP 3: CONSTANTS AND ARITHMETIC OPERATORS
// ============================================

echo '<div class="section">';
echo '<h2>Step 3: Constants and Arithmetic Operators</h2>';

// Defining constants
define('TAX_RATE', 0.22);
define('OVERTIME_MULTIPLIER', 1.5);
const STANDARD_HOURS = 40;

echo '<p class="label">Constants (cannot be changed once set):</p>';
echo '<p>TAX_RATE: <span class="result">' . TAX_RATE . '</span> (22%)</p>';
echo '<p>OVERTIME_MULTIPLIER: <span class="result">' . OVERTIME_MULTIPLIER . '</span></p>';
echo '<p>STANDARD_HOURS: <span class="result">' . STANDARD_HOURS . '</span></p>';

What does this code do?

  • define('TAX_RATE', 0.22) creates a constant at run-time. The value 0.22 represents a 22% tax rate and can never be changed after this line.
  • const STANDARD_HOURS = 40 creates a constant at compile-time. It works the same as define() at the top level of a script, but cannot be used inside functions or loops.
  • Constants have no $ prefix, are uppercase by convention, and are accessible globally from anywhere in your script.

What happens if you try to reassign a constant?

PHP throws an error. Once a constant is set, it is locked for the rest of the script. This is exactly why constants are perfect for values like tax rates that should never change accidentally during execution.

  • Save index.php and refresh your browser at http://localhost/paycheck/index.php.
  • You should see a new white section titled "Step 3: Constants and Arithmetic Operators" displaying the three constant values: 0.22, 1.5, and 40.

Seeing a blank page or an error?

  • Check that you placed the new code after Step 2's echo '</div>'; but before the ?> closing tag.
  • Make sure the constant names inside define() are wrapped in single quotes. Missing quotes will cause a PHP error.
  • Confirm Apache is still running in the XAMPP Control Panel.

Why aren't my PHP constants showing in the browser?

Calculate the paycheck using arithmetic operators

With employee data in variables and fixed rates in constants, you can now calculate the actual paycheck. PHP provides all the standard arithmetic operators plus a power operator for exponentiation.

  • Add the following code below the last echo line that displays STANDARD_HOURS:
// Arithmetic operators
$grossPay = $hourlyRate * $hoursWorked;
$taxAmount = $grossPay * TAX_RATE;
$netPay = $grossPay - $taxAmount;

echo '<p class="label">Arithmetic calculations:</p>';
echo '<p>Gross Pay ($hourlyRate * $hoursWorked): <span class="result">$' . $grossPay . '</span></p>';
echo '<p>Tax Amount ($grossPay * TAX_RATE): <span class="result">$' . $taxAmount . '</span></p>';
echo '<p>Net Pay ($grossPay - $taxAmount): <span class="result">$' . $netPay . '</span></p>';

// Exponentiation operator
$savings = 1000 * (1.05 ** 3);
echo '<p>Compound interest (1000 * 1.05^3): <span class="result">$' . round($savings, 2) . '</span></p>';

What does this code do?

  • $grossPay = $hourlyRate * $hoursWorked multiplies the rate by hours to get total earnings before deductions.
  • $taxAmount = $grossPay * TAX_RATE calculates 22% of gross pay as tax. Notice how you mix a variable ($grossPay) with a constant (TAX_RATE) in the same expression.
  • The ** operator raises a number to a power. Here 1.05 ** 3 calculates 5% compound interest over 3 years.
  • round($savings, 2) rounds the result to 2 decimal places for clean currency display.
  • Save index.php and refresh your browser.
  • You should see Gross Pay as $1147.5, Tax Amount as $252.45, Net Pay as $895.05, and Compound interest as $1157.63.

Numbers not matching?

  • Make sure $hourlyRate is still set to 25.50 and $hoursWorked is 45 from Step 2. If you changed those values while experimenting, reset them.
  • Check that TAX_RATE is defined as 0.22 (not 22). The decimal form represents a percentage.

Help me debug my PHP arithmetic calculations.

Explore modulo and operator precedence

The modulo operator returns the remainder after division. Operator precedence determines which math happens first when multiple operators appear in one expression.

  • Add the following code below the compound interest echo line:
// Modulo operator
$remainderHours = $hoursWorked % 5;
echo '<p>Hours modulo 5 ($hoursWorked % 5): <span class="result">' . $remainderHours . '</span> (remainder hours after full 5-day splits)</p>';

// Operator precedence
$withoutParens = 2 + 3 * 4;
$withParens = (2 + 3) * 4;
echo '<p class="label">Operator precedence:</p>';
echo '<p>2 + 3 * 4 = <span class="result">' . $withoutParens . '</span> (multiplication first)</p>';
echo '<p>(2 + 3) * 4 = <span class="result">' . $withParens . '</span> (parentheses force addition first)</p>';

echo '</div>';

What does this code do?

  • $hoursWorked % 5 divides 45 by 5 and returns the remainder (0). This tells you whether hours split evenly into 5-day work weeks.
  • 2 + 3 * 4 equals 14 because PHP evaluates multiplication before addition, just like standard math.
  • (2 + 3) * 4 equals 20 because parentheses force the addition to happen first.
  • echo '</div>'; closes the Step 3 HTML section container.
  • Save index.php and refresh your browser.
  • You should now see the modulo result (0) and both operator precedence results (14 and 20) displayed at the bottom of the Step 3 section.

Seeing unexpected modulo results?

  • The % operator returns the remainder, not the quotient. 45 divided by 5 is 9 with remainder 0.
  • If you see a syntax error, check that you have not accidentally used ^ for exponentiation. In PHP, ^ is a bitwise XOR operator. Use ** for powers.

Help me understand PHP's modulo and precedence operators.

✔️ Awesome, I've got everything!

Great. Double check you have saved your file before moving on.

ⓧ I'd like to double check the full code

Here is the complete index.php file at the end of this step. Compare yours against it:

<!DOCTYPE html>
<html>
<head>
    <title>Paycheck Calculator</title>
    <style>
        body { font-family: Arial, sans-serif; margin: 40px; background: #f5f5f5; }
        h1 { color: #2c3e50; }
        h2 { color: #34495e; margin-top: 30px; }
        .section { background: white; padding: 20px; margin: 20px 0; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
        .result { color: #27ae60; font-weight: bold; }
        .label { color: #7f8c8d; }
        code { background: #ecf0f1; padding: 2px 6px; border-radius: 3px; }
    </style>
</head>
<body>

<h1>Paycheck Calculator</h1>

<?php
// ============================================
// STEP 2: VARIABLES AND DATA TYPES
// ============================================

echo '<div class="section">';
echo '<h2>Step 2: Variables and Data Types</h2>';

$employeeName = "Alice Johnson";
$hourlyRate = 25.50;
$hoursWorked = 45;
$isFullTime = true;
$middleName = null;

echo '<p class="label">var_dump of each variable:</p>';
echo '<pre>';
echo '$employeeName: '; var_dump($employeeName);
echo '$hourlyRate: '; var_dump($hourlyRate);
echo '$hoursWorked: '; var_dump($hoursWorked);
echo '$isFullTime: '; var_dump($isFullTime);
echo '$middleName: '; var_dump($middleName);
echo '</pre>';

$hoursAsString = "40";
echo '<p class="label">Type difference demo:</p>';
echo '<pre>';
echo '"40" as string: '; var_dump($hoursAsString);
echo '40 as integer: '; var_dump($hoursWorked);
echo '</pre>';

$deductions = ["tax", "insurance", "retirement"];
echo '<p class="label">Array variable:</p>';
echo '<pre>';
var_dump($deductions);
echo '</pre>';

echo '<p class="label">Formatted output using concatenation (.):</p>';
echo '<p>Employee: <span class="result">' . $employeeName . '</span></p>';
echo '<p>Hourly Rate: <span class="result">$' . $hourlyRate . '</span></p>';
echo '<p>Hours Worked: <span class="result">' . $hoursWorked . '</span></p>';
echo '<p>Full Time: <span class="result">' . ($isFullTime ? 'Yes' : 'No') . '</span></p>';
echo '<p>Middle Name: <span class="result">' . ($middleName ?? 'Not set (null)') . '</span></p>';

echo '</div>';

// ============================================
// STEP 3: CONSTANTS AND ARITHMETIC OPERATORS
// ============================================

echo '<div class="section">';
echo '<h2>Step 3: Constants and Arithmetic Operators</h2>';

define('TAX_RATE', 0.22);
define('OVERTIME_MULTIPLIER', 1.5);
const STANDARD_HOURS = 40;

echo '<p class="label">Constants (cannot be changed once set):</p>';
echo '<p>TAX_RATE: <span class="result">' . TAX_RATE . '</span> (22%)</p>';
echo '<p>OVERTIME_MULTIPLIER: <span class="result">' . OVERTIME_MULTIPLIER . '</span></p>';
echo '<p>STANDARD_HOURS: <span class="result">' . STANDARD_HOURS . '</span></p>';

$grossPay = $hourlyRate * $hoursWorked;
$taxAmount = $grossPay * TAX_RATE;
$netPay = $grossPay - $taxAmount;

echo '<p class="label">Arithmetic calculations:</p>';
echo '<p>Gross Pay ($hourlyRate * $hoursWorked): <span class="result">$' . $grossPay . '</span></p>';
echo '<p>Tax Amount ($grossPay * TAX_RATE): <span class="result">$' . $taxAmount . '</span></p>';
echo '<p>Net Pay ($grossPay - $taxAmount): <span class="result">$' . $netPay . '</span></p>';

$savings = 1000 * (1.05 ** 3);
echo '<p>Compound interest (1000 * 1.05^3): <span class="result">$' . round($savings, 2) . '</span></p>';

$remainderHours = $hoursWorked % 5;
echo '<p>Hours modulo 5 ($hoursWorked % 5): <span class="result">' . $remainderHours . '</span> (remainder hours after full 5-day splits)</p>';

$withoutParens = 2 + 3 * 4;
$withParens = (2 + 3) * 4;
echo '<p class="label">Operator precedence:</p>';
echo '<p>2 + 3 * 4 = <span class="result">' . $withoutParens . '</span> (multiplication first)</p>';
echo '<p>(2 + 3) * 4 = <span class="result">' . $withParens . '</span> (parentheses force addition first)</p>';

echo '</div>';
?>

</body>
</html>

Your paycheck calculator now crunches real numbers. Next up, you will use comparison and logical operators to make decisions about overtime eligibility and bonus qualification.

Apply Comparison and Logical Operators

Your calculator can crunch numbers, but it cannot yet make decisions. Real paychecks need logic: does this employee qualify for overtime? Should they receive a bonus?

In this step, you will use comparison operators to evaluate conditions and logical operators to combine those conditions. Together, they let your script make smart decisions about the paycheck output.

In this step, get ready to:
  • Use comparison operators to check overtime eligibility and demonstrate loose vs strict equality.
  • Combine conditions with logical operators to determine bonus and insurance eligibility.
  • Build a final paycheck summary using an if/else block that calculates overtime pay.
Use comparison operators to evaluate conditions

Comparison operators ask yes-or-no questions about values. The answer is always a boolean: true or false. PHP has a unique twist here: loose equality (==) converts types before comparing, while strict equality (===) requires both the value and the type to match.

  • In index.php, find the closing echo '</div>'; line at the end of the Step 3 section.
  • Add the following code below that line to start a new section and demonstrate comparison operators:
// ============================================
// STEP 4: COMPARISON AND LOGICAL OPERATORS
// ============================================

echo '<div class="section">';
echo '<h2>Step 4: Comparison and Logical Operators</h2>';

// Comparison operators
$workedOvertime = $hoursWorked > STANDARD_HOURS;
echo '<p class="label">Comparison operators:</p>';
echo '<pre>';
echo '$hoursWorked > STANDARD_HOURS: '; var_dump($workedOvertime);
echo '40 == "40" (loose comparison): '; var_dump(40 == "40");
echo '40 === "40" (strict comparison): '; var_dump(40 === "40");
echo '40 != 50: '; var_dump(40 != 50);
echo '40 !== "40": '; var_dump(40 !== "40");
echo '$hoursWorked >= 40: '; var_dump($hoursWorked >= 40);
echo '45 <=> 40 (spaceship): '; var_dump(45 <=> 40);
echo '40 <=> 40 (spaceship): '; var_dump(40 <=> 40);
echo '35 <=> 40 (spaceship): '; var_dump(35 <=> 40);
echo '</pre>';

What does this code do?

Each line uses var_dump() to show the boolean result of a comparison.

  • $workedOvertime = $hoursWorked > STANDARD_HOURS stores whether hours (45) exceed the standard (40). The result is true.
  • 40 == "40" is true because PHP converts the string to a number before comparing. 40 === "40" is false because strict comparison checks type too.
  • The spaceship operator <=> returns -1 (left is smaller), 0 (equal), or 1 (left is larger). This is a PHP-specific operator useful for sorting.
  • Save index.php and refresh your browser at http://localhost/paycheck/index.php.
  • You should see a new "Step 4" section with a list of comparison results. Each line shows the expression, then bool(true) or bool(false).

Not seeing the Step 4 section?

  • Make sure you pasted the new code after the last echo '</div>'; from Step 3, but still inside the ?> closing tag.
  • Check for mismatched quotes. Each echo line must have matching opening and closing single quotes around the string.

Help me debug my comparison operators section in PHP.

Why does === matter?

PHP's loose comparison (==) silently converts types, which can cause subtle bugs. For example, a form input might send the string "0" and accidentally match the integer 0.

Using === catches these mismatches early. Professional PHP code overwhelmingly uses strict comparison to avoid type-juggling surprises.

Combine conditions with logical operators

A single comparison answers one question. Logical operators let you combine multiple questions into a single decision. For example: does the employee qualify for a bonus if they are full-time AND worked overtime?

  • In index.php, add the following code directly below the closing echo '</pre>'; line from the comparison operators section above:
// Logical operators
$getsBonus = $isFullTime && $workedOvertime;
$qualifiesForInsurance = $isFullTime || $hoursWorked >= 30;
$isPartTime = !$isFullTime;

echo '<p class="label">Logical operators:</p>';
echo '<pre>';
echo '$isFullTime && $workedOvertime (AND): '; var_dump($getsBonus);
echo '$isFullTime || $hoursWorked >= 30 (OR): '; var_dump($qualifiesForInsurance);
echo '!$isFullTime (NOT): '; var_dump($isPartTime);
echo '</pre>';

What does this code do?

  • && (AND) requires both sides to be true. Since Alice is full-time AND worked overtime, $getsBonus is true.
  • || (OR) requires at least one side to be true. Alice qualifies for insurance because she is full-time.
  • ! (NOT) flips a boolean. Since $isFullTime is true, $isPartTime becomes false.

PHP uses short-circuit evaluation. In $a && $b, if $a is false, PHP skips checking $b entirely because the overall result is already guaranteed to be false.

  • Save index.php and refresh your browser.
  • Below the comparison results, you should see three logical operator results. All three display bool(true) for AND and OR, and bool(false) for NOT.

Seeing unexpected boolean values?

  • Double check that $isFullTime is set to true (no quotes) in your Step 2 variables. Quotes would make it a string, not a boolean.
  • Make sure $hoursWorked is set to 45 (greater than 40). If it is 40 or lower, the overtime check will be false.

Help me understand why my logical operator results are wrong.

How PHP logical operators differ from JavaScript

In JavaScript, || returns the first truthy value (not just true or false). PHP's || always returns a boolean. If you want JavaScript-style default values in PHP, use the null coalescing operator ?? instead.

Build the final paycheck output with overtime logic

Now you will combine everything into a real paycheck decision. An if/else block lets your script choose a different calculation path depending on whether the employee worked overtime.

  • In index.php, add the following code below the logical operators echo '</pre>'; line you just wrote:
// Final paycheck with overtime calculation
echo '<p class="label">Final Paycheck Calculation:</p>';

if ($workedOvertime) {
    $regularPay = STANDARD_HOURS * $hourlyRate;
    $overtimeHours = $hoursWorked - STANDARD_HOURS;
    $overtimePay = $overtimeHours * $hourlyRate * OVERTIME_MULTIPLIER;
    $grossPay = $regularPay + $overtimePay;
    $taxAmount = $grossPay * TAX_RATE;
    $netPay = $grossPay - $taxAmount;

    echo '<p>Status: <span class="result">OVERTIME</span></p>';
    echo '<p>Regular Pay (40 hrs): <span class="result">$' . $regularPay . '</span></p>';
    echo '<p>Overtime Hours: <span class="result">' . $overtimeHours . '</span></p>';
    echo '<p>Overtime Pay (' . $overtimeHours . ' hrs x $' . $hourlyRate . ' x ' . OVERTIME_MULTIPLIER . '): <span class="result">$' . $overtimePay . '</span></p>';
} else {
    $grossPay = $hoursWorked * $hourlyRate;
    $taxAmount = $grossPay * TAX_RATE;
    $netPay = $grossPay - $taxAmount;

    echo '<p>Status: <span class="result">REGULAR</span></p>';
}

echo '<p>Gross Pay: <span class="result">$' . $grossPay . '</span></p>';
echo '<p>Tax (' . (TAX_RATE * 100) . '%): <span class="result">-$' . $taxAmount . '</span></p>';
echo '<p>Net Pay: <span class="result">$' . $netPay . '</span></p>';
echo '<p>Bonus Eligible: <span class="result">' . ($getsBonus ? 'YES' : 'NO') . '</span></p>';
echo '<p>Insurance Eligible: <span class="result">' . ($qualifiesForInsurance ? 'YES' : 'NO') . '</span></p>';

echo '</div>';

What does this code do?

  • The if ($workedOvertime) block runs only when the employee exceeded 40 hours. It calculates regular pay for the first 40 hours, then applies the 1.5x overtime multiplier to the extra hours.
  • The else block handles the simpler case where hours are at or below 40. It calculates straight pay without overtime.
  • The lines after the if/else block run regardless of which path executed. They display the gross pay, tax, net pay, and eligibility results using the ternary operator (? 'YES' : 'NO') to convert booleans into readable text.
  • Save index.php and refresh your browser.
  • You should see a "Final Paycheck Calculation" section with status OVERTIME, regular pay of $1020, overtime hours of 5, overtime pay of $191.25, gross pay of $1191.25, and a net pay after the 22% tax deduction.
  • Bonus Eligible should show YES and Insurance Eligible should show YES.

Seeing a blank page or an error?

  • A blank page usually means a syntax error. Check that every opening curly brace { has a matching closing brace } in your if/else block.
  • Look for missing dots (.) in the concatenation. Every time you join a variable to a string, you need a dot on both sides of the variable.
  • Make sure each echo line ends with a semicolon.

Help me fix my if/else paycheck calculation code.

✔️ Awesome, I've got everything!

Great. Double check you have saved index.php and your browser shows the complete paycheck output with overtime details.

ⓧ I'd like to double check the full code

Here is the complete index.php file as it should look at the end of this step. Compare it against yours:

<!DOCTYPE html>
<html>
<head>
    <title>Paycheck Calculator</title>
    <style>
        body { font-family: Arial, sans-serif; margin: 40px; background: #f5f5f5; }
        h1 { color: #2c3e50; }
        h2 { color: #34495e; margin-top: 30px; }
        .section { background: white; padding: 20px; margin: 20px 0; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
        .result { color: #27ae60; font-weight: bold; }
        .label { color: #7f8c8d; }
        code { background: #ecf0f1; padding: 2px 6px; border-radius: 3px; }
    </style>
</head>
<body>

<h1>Paycheck Calculator</h1>

<?php
// ============================================
// STEP 2: VARIABLES AND DATA TYPES
// ============================================

echo '<div class="section">';
echo '<h2>Step 2: Variables and Data Types</h2>';

$employeeName = "Alice Johnson";
$hourlyRate = 25.50;
$hoursWorked = 45;
$isFullTime = true;
$middleName = null;

echo '<p class="label">var_dump of each variable:</p>';
echo '<pre>';
echo '$employeeName: '; var_dump($employeeName);
echo '$hourlyRate: '; var_dump($hourlyRate);
echo '$hoursWorked: '; var_dump($hoursWorked);
echo '$isFullTime: '; var_dump($isFullTime);
echo '$middleName: '; var_dump($middleName);
echo '</pre>';

$hoursAsString = "40";
echo '<p class="label">Type difference demo:</p>';
echo '<pre>';
echo '"40" as string: '; var_dump($hoursAsString);
echo '40 as integer: '; var_dump($hoursWorked);
echo '</pre>';

$deductions = ["tax", "insurance", "retirement"];
echo '<p class="label">Array variable:</p>';
echo '<pre>';
var_dump($deductions);
echo '</pre>';

echo '<p class="label">Formatted output using concatenation (.):</p>';
echo '<p>Employee: <span class="result">' . $employeeName . '</span></p>';
echo '<p>Hourly Rate: <span class="result">$' . $hourlyRate . '</span></p>';
echo '<p>Hours Worked: <span class="result">' . $hoursWorked . '</span></p>';
echo '<p>Full Time: <span class="result">' . ($isFullTime ? 'Yes' : 'No') . '</span></p>';
echo '<p>Middle Name: <span class="result">' . ($middleName ?? 'Not set (null)') . '</span></p>';

echo '</div>';

// ============================================
// STEP 3: CONSTANTS AND ARITHMETIC OPERATORS
// ============================================

echo '<div class="section">';
echo '<h2>Step 3: Constants and Arithmetic Operators</h2>';

define('TAX_RATE', 0.22);
define('OVERTIME_MULTIPLIER', 1.5);
const STANDARD_HOURS = 40;

echo '<p class="label">Constants (cannot be changed once set):</p>';
echo '<p>TAX_RATE: <span class="result">' . TAX_RATE . '</span> (22%)</p>';
echo '<p>OVERTIME_MULTIPLIER: <span class="result">' . OVERTIME_MULTIPLIER . '</span></p>';
echo '<p>STANDARD_HOURS: <span class="result">' . STANDARD_HOURS . '</span></p>';

$grossPay = $hourlyRate * $hoursWorked;
$taxAmount = $grossPay * TAX_RATE;
$netPay = $grossPay - $taxAmount;

echo '<p class="label">Arithmetic calculations:</p>';
echo '<p>Gross Pay ($hourlyRate * $hoursWorked): <span class="result">$' . $grossPay . '</span></p>';
echo '<p>Tax Amount ($grossPay * TAX_RATE): <span class="result">$' . $taxAmount . '</span></p>';
echo '<p>Net Pay ($grossPay - $taxAmount): <span class="result">$' . $netPay . '</span></p>';

$savings = 1000 * (1.05 ** 3);
echo '<p>Compound interest (1000 * 1.05^3): <span class="result">$' . round($savings, 2) . '</span></p>';

$remainderHours = $hoursWorked % 5;
echo '<p>Hours modulo 5 ($hoursWorked % 5): <span class="result">' . $remainderHours . '</span> (remainder hours after full 5-day splits)</p>';

$withoutParens = 2 + 3 * 4;
$withParens = (2 + 3) * 4;
echo '<p class="label">Operator precedence:</p>';
echo '<p>2 + 3 * 4 = <span class="result">' . $withoutParens . '</span> (multiplication first)</p>';
echo '<p>(2 + 3) * 4 = <span class="result">' . $withParens . '</span> (parentheses force addition first)</p>';

echo '</div>';

// ============================================
// STEP 4: COMPARISON AND LOGICAL OPERATORS
// ============================================

echo '<div class="section">';
echo '<h2>Step 4: Comparison and Logical Operators</h2>';

$workedOvertime = $hoursWorked > STANDARD_HOURS;
echo '<p class="label">Comparison operators:</p>';
echo '<pre>';
echo '$hoursWorked > STANDARD_HOURS: '; var_dump($workedOvertime);
echo '40 == "40" (loose comparison): '; var_dump(40 == "40");
echo '40 === "40" (strict comparison): '; var_dump(40 === "40");
echo '40 != 50: '; var_dump(40 != 50);
echo '40 !== "40": '; var_dump(40 !== "40");
echo '$hoursWorked >= 40: '; var_dump($hoursWorked >= 40);
echo '45 <=> 40 (spaceship): '; var_dump(45 <=> 40);
echo '40 <=> 40 (spaceship): '; var_dump(40 <=> 40);
echo '35 <=> 40 (spaceship): '; var_dump(35 <=> 40);
echo '</pre>';

$getsBonus = $isFullTime && $workedOvertime;
$qualifiesForInsurance = $isFullTime || $hoursWorked >= 30;
$isPartTime = !$isFullTime;

echo '<p class="label">Logical operators:</p>';
echo '<pre>';
echo '$isFullTime && $workedOvertime (AND): '; var_dump($getsBonus);
echo '$isFullTime || $hoursWorked >= 30 (OR): '; var_dump($qualifiesForInsurance);
echo '!$isFullTime (NOT): '; var_dump($isPartTime);
echo '</pre>';

echo '<p class="label">Final Paycheck Calculation:</p>';

if ($workedOvertime) {
    $regularPay = STANDARD_HOURS * $hourlyRate;
    $overtimeHours = $hoursWorked - STANDARD_HOURS;
    $overtimePay = $overtimeHours * $hourlyRate * OVERTIME_MULTIPLIER;
    $grossPay = $regularPay + $overtimePay;
    $taxAmount = $grossPay * TAX_RATE;
    $netPay = $grossPay - $taxAmount;

    echo '<p>Status: <span class="result">OVERTIME</span></p>';
    echo '<p>Regular Pay (40 hrs): <span class="result">$' . $regularPay . '</span></p>';
    echo '<p>Overtime Hours: <span class="result">' . $overtimeHours . '</span></p>';
    echo '<p>Overtime Pay (' . $overtimeHours . ' hrs x $' . $hourlyRate . ' x ' . OVERTIME_MULTIPLIER . '): <span class="result">$' . $overtimePay . '</span></p>';
} else {
    $grossPay = $hoursWorked * $hourlyRate;
    $taxAmount = $grossPay * TAX_RATE;
    $netPay = $grossPay - $taxAmount;

    echo '<p>Status: <span class="result">REGULAR</span></p>';
}

echo '<p>Gross Pay: <span class="result">$' . $grossPay . '</span></p>';
echo '<p>Tax (' . (TAX_RATE * 100) . '%): <span class="result">-$' . $taxAmount . '</span></p>';
echo '<p>Net Pay: <span class="result">$' . $netPay . '</span></p>';
echo '<p>Bonus Eligible: <span class="result">' . ($getsBonus ? 'YES' : 'NO') . '</span></p>';
echo '<p>Insurance Eligible: <span class="result">' . ($qualifiesForInsurance ? 'YES' : 'NO') . '</span></p>';

echo '</div>';
?>

</body>
</html>

Your paycheck calculator now makes real decisions. It detects overtime, calculates the correct pay path, and determines eligibility for bonuses and insurance. Next up, you will take on the Secret Mission and build a multi-employee comparison table.

Secret mission

Build a Multi-Employee Comparison Table

What if your paycheck calculator needs to handle more than one employee? In this challenge, you'll store employee data in associative arrays, calculate pay for each person independently, and build a dynamic HTML comparison table that highlights who earned more.

Clean Up Your Resources

Clean Up Your Resources

This project runs entirely locally using XAMPP, so there are no ongoing costs. Decide whether to keep your files for reference or delete them for a clean slate.

Resources you used:

  • The paycheck folder in C:\xampp\htdocs.
  • XAMPP Apache server (currently running).

Keep everything running

No action needed. Choose this if you plan to keep practising PHP or want to reference your paycheck calculator later.

  • Your paycheck folder stays in C:\xampp\htdocs and remains accessible at http://localhost/paycheck/index.php whenever Apache is running.
  • Apache continues running in the background via the XAMPP Control Panel.

Pause - I'll come back to this later

Stop Apache to free up the port, but keep your project files for next time.

  • Open the XAMPP Control Panel.
  • Click Stop next to Apache.
  • Your paycheck folder remains in C:\xampp\htdocs ready for when you return.
  • To resume later, open XAMPP and click Start next to Apache again.

Delete - I don't want to use this again

Remove your project files and stop Apache to start fresh.

  • Open the XAMPP Control Panel and click Stop next to Apache.
  • Delete the paycheck folder from C:\xampp\htdocs. You can do this from File Explorer or by running this command in Command Prompt:
rmdir /s /q C:\xampp\htdocs\paycheck
  • Confirm the folder is gone by checking C:\xampp\htdocs in File Explorer. You should no longer see a paycheck folder.

Nice Work!

Nice Work!

You just built a fully functional PHP paycheck calculator from scratch. It runs in your browser, calculates real numbers, and makes decisions based on employee data.

You learned how to:

  • Built a working PHP paycheck calculator using variables, constants, and all core data types (string, int, float, bool, null, and array).
  • Applied every arithmetic operator (+, -, *, /, %, **) to calculate gross pay, tax deductions, overtime, and net pay.
  • Used comparison operators (including PHP-specific === and <=>) and logical operators (&&, ||, !) to determine overtime eligibility and bonus qualification.
  • Secret Mission: Built a multi-employee comparison table using associative arrays and the ternary operator.

Ready to quiz yourself?