Essential PHP Course: The Direct Route to Laravel and CodeIgniter
Tools Needed for the Mini-Course
In this section, we'll talk about the tools we will need to carry out this mini-course.
Code Editor
As I always recommend, the most practical thing is to use a code editor. I use Visual Studio Code (VS Code), which looks like this. I have a Python project with Flash open here, but this interface is the same for any type of project.
It is not mandatory to use VS Code; you could even program in Notepad, although that would be quite masochistic of you. I recommend using a high-quality editor, like VS Code, for several reasons:
- It is cross-platform.
- It supports multiple technologies.
- It is stable and works very well on large projects.
If you decide to use VS Code, the only extension you need to install is the PHP one. You can search for it in the extensions section; it's usually called “PHP” and requires no additional configuration.
Web Browser
You can use the browser you prefer. I use Google Chrome, but any modern browser will work perfectly for this course.
PHP and Development Environment
PHP is essential for this course, and there are many ways to install it, depending on the operating system:
Windows or macOS: I recommend Laravel Herd, which is easy to install and configure. Although its name may sound advanced, it's very intuitive and will allow you to have everything ready to work with PHP, Laravel, or CodeIgniter projects.
Linux: Installation here depends on the distribution and requires specific commands. For example, you could use XAMPP, LAMP, or consult guides for your operating system.
Laravel Herd and similar tools facilitate development, as they automatically create clean URLs for your projects, unlike other environments like XAMPP or WAMP, where everything is manual.
Hello World
Previous steps:
- Start the server. The next thing you need to do is start your server.
If you use Laravel Herd, all necessary services will start automatically when you open it. For others, like XAMPP, there's usually a button that says 'Start'. You must be aware of any errors, such as if a port is already in use, etc. Remember that you can ONLY have one XAMPP-like service such as Laragon or Laravel Herd active at a time.- Once started, when you open localhost in your browser, you should see a welcome page from your server (Apache, Nginx, or whichever you use).
- Editor, select your editor, the recommended VSC, and create a folder on your server:
- If you are using Laragon or Herd, the default path would be something like:
- C:\Users\YourUser\Laragon\www
- C:\Users\YourUser\Herd
- Create a folder, suggested named “tests” (or "pruebas" if you prefer to keep the original name) and drag it to your VSC.
- If you are using Laragon or Herd, the default path would be something like:
Writing our first “Hello World”
In PHP, all code goes inside the tags:
C:\Users\YourUser\Herd\test.php
<?php
// Your PHP code goes hereTo display text on the screen, we use the echo function.
For example:
C:\Users\YourUser\Herd\test.php
<?php echo "Hello World";The quotes can be single 'Hello World' or double "Hello World".
Each instruction must end with a semicolon ;.
Save the file and reload the page in your browser, in Laravel Herd or Laragon:
http://tests.test/test.php (or http://pruebas.test/test.php)
Others:
http://localhost/tests/test.php (or http://localhost/pruebas/test.php)
There you have your first “Hello World” in PHP! 🎉
First Steps with PHP
We are at the point where we have already learned how to display our first Hello World in PHP without complications.
Remember that, to work with PHP and place any dynamic content, we must always use the opening tag <?php ?>. From here, we can take advantage of the full potential of PHP, which allows us to perform dynamic operations, work with object-oriented programming, manage dates, variables, classes, and much more. We will be covering all of this little by little throughout the course.
My goal is not just to teach you how to create variables or functions, but to give you the foundations to understand the logical reasoning behind each action, and to understand the “why” of what we are doing.
RECOMMENDATION: Viewing the Page Source in the Browser
Before moving on, it's advisable to always check the page's source code:
On Windows or Linux: right-click → View page source
On Mac: Ctrl + U
The browser only understands HTML, CSS, and JavaScript, plus static files like PDFs, images, or videos. Everything that PHP generates is interpreted on the server and sent as HTML to the browser. For example, even if your file is PHP, the browser only renders HTML.
Looking at the source code is a useful tool for you to see exactly what is being rendered.
HTML vs PHP
To illustrate this, we can create a file test2.html with the same message we put in PHP. When you open it, you will see that the output in the browser is the same, although the path changes.
This demonstrates a key principle: the browser only understands HTML, CSS, and JavaScript. PHP serves to add dynamism to these pages, for example:
<?php echo 5 + 5; // This will display 10 ?>With PHP we can:
- Perform dynamic operations
- Display dates
- Connect to databases
Create dynamic content that is then served as HTML
In contrast, if we try to place operations like 5 + 5 with PHP directly in an HTML file, the browser will not know what to do and will simply display it as text.
Best Practices with PHP Tags
When mixing PHP with HTML, it is important to correctly close the tags.
Example:
<?php echo "Hello World"; ?> <h1>This is an HTML title</h1>The opening <?php indicates the start of the PHP code.
The closing ?> is necessary if HTML content follows.
If the entire file is pure PHP, it is not mandatory to close the tag, and in fact, it is often recommended not to close it to avoid accidental whitespace or injections.
Spaghetti Code in PHP
When we mix logic, HTML, and operations in a single file, we get what is known as spaghetti code:
- Business logic
- Database connections
- User validations
- Static HTML
This works, but it is difficult to maintain and prone to errors. That's why, even though we must learn “pure” PHP to understand the basics, the ideal is to use a framework.
Frameworks to Avoid Spaghetti Code
A framework allows us to:
- Automatically follow best practices
- Separate logic from presentation
- Avoid common errors in pure PHP
Examples of lightweight frameworks we can use to learn:
- Laravel
- CodeIgniter
- Lumen
These frameworks help us create structured and maintainable applications, preventing us from ending up with a single file full of mixed PHP and HTML.
Summary
- PHP is interpreted on the server and delivers HTML to the browser.
- Always use <?php ?> for PHP code.
- Check the browser's source code to understand what is actually sent.
- Close PHP tags if you combine with HTML.
- Avoid spaghetti code by using frameworks.
With this, we have a solid foundation to start working with PHP correctly, understanding the difference between static and dynamic content, and prepared to advance toward more complex operations and the use of frameworks.
Variables in PHP
In this section, we will talk about variables in PHP. Honestly, the data types part doesn't make much sense in this context, as this is a fairly old article that I am updating. But back to the topic: I assume you already know how to program and are here to learn PHP and take the next step, which is then jumping to frameworks, which is one of the goals of this course.
Even so, let's quickly give a definition of a variable:
A variable is simply a way to access memory. That is, we have a piece of information (an integer, a string, a boolean, etc.) and we want to store it so we can use it throughout our application.
For example, suppose you are creating a form to request a person's details, such as name, age, etc. Each of these details can be stored in a variable, such as:
- A variable for the name
- A variable for the age
The use you make of these variables will depend on the purpose of your application, the business logic, and so on. In general terms, this is what a variable is.
Variable Syntax in PHP
In PHP, all variables begin with the $ symbol. This is an interesting peculiarity of PHP, as most other languages like Java, JavaScript, C#, among others, do not use the $.
Some important rules:
- They cannot contain spaces. For example, person name is not valid.
- They cannot start with numbers or special characters.
You can use letters, underscores \_, or uppercase letters, following naming conventions:
- Camel case: personName
- Snake case: person_name
Personally, I prefer camel case, but it's a matter of preference. The important thing is to maintain consistency and readability.
Data Types and Best Practices
In PHP, the data type is optional when declaring a variable, unlike other languages like Java or C#. However, it is always recommended to specify it. For example:
$name = "Andrés"; // string
$edad = 25; // integer
$activo = true; // booleanWe can check the data type using the gettype() function:
echo gettype($name); // string
echo gettype($edad); // integerIt is important to remember:
- Do not declare crazy or illegal names for variables.
- Do not use spaces or strange characters.
- You can include numbers after the first letter if necessary.
Types of Variables in PHP
Variables are the mechanism to access memory that programming languages make available to us; in this article we will see how to create a variable in PHP, its particularities, and data types in PHP.
Variable names in PHP must start with the '$' sign (without quotes) followed by the name of the variable, which cannot be null, nor begin with a number or a special character.
Example of Invalid Variables in PHP
$1var; // no puede comenzar por un numero
$ var; // no puede comenzar con un espacio vacio
$v ar // tampoco puede contener espacios vacios
var // falto el $Example of Valid Variables in PHP
$var;
$var1;
$_var;They are case-sensitive.
Example of Distinct Variables in PHP
$Var;
$VAr;
$var;In PHP it is not necessary to specify the data type before using them; they are declared when a value is assigned to them.
PHP Supports Eight Primitive Types
Four scalar types:
Two compound types:
- object
- array
And two special types:
Finally, we present a simple example of a person's data using several of the variable types we have already seen.
<?php
$age = 24; // Integer type variable.
$name = "pepe"; // String type variable.
$married = true; // Boolean type variable.
$salary = 4025.43; // Float type variable.
// Array of 4 data types
$person_array = array('age' => $age, 'name' => $name, 'married' => $married, 'salary' => $salary);
// Object of 4 data types
$person_object = (object)$person_array;
// We display the values of the variables
echo "Integer type variable: ";
echo $age;
echo "<br>";
echo "String type variable: ";
echo $name;
echo "<br>";
echo "Boolean variable: ";
echo $married;
echo "<br>";
echo "Double type variable: ";
echo $salary;
echo "<br>";
echo "Object type variable: ";
echo $person_object->age;
echo "-";
echo $person_object->name;
echo "-";
echo $person_object->married;
echo "-";
echo $person_object->salary;
echo "<br>";
echo "Array type variable:";
echo "<br>";
var_dump($person_array);
?>Interpreting the code above:
variable de tipo integer: 24
variable de tipo string: pepe
variable boolean: 1
variable de tipo double: 4025.43
variable de tipo object: 24-pepe-1-4025.43
variable de tipo array:
array(4) { ["anos"]=> int(24) ["nombre"]=> string(4) "pepe" ["casado"]=> bool(true) ["sueldo"]=> float(4025.43) }Booleans in PHP
This is the simplest data type that exists in PHP; a boolean expresses a truth value, which can only have one of two states: TRUE or FALSE; in both cases, they are case-insensitive.
<?php
$verdad = TRUE; // asigna el valor TRUE
$falso = FALSE; // asigna el valor FALSE
?>TRUE is equivalent to the value 1 and FALSE is equivalent to the value 0; that is, you can replace the value 1 and 0 with TRUE and FALSE respectively.
Integer in PHP
An integer is by definition a signed number without a decimal part; the same rule applies in PHP.
Notations for Integers in PHP
Integers can be specified using decimal (base 10), hexadecimal (base 16), octal (base 8), or binary (base 2) notation, optionally preceded by a sign (- or +) as the case may be:
- To use octal notation, the number is preceded by a 0 (zero).
- To use hexadecimal notation, the number is preceded by a 0x.
- To use binary notation, the number is preceded by a 0b.
Example: Integer Literals in PHP
<?php
$a = 1234; // decimal number
var_dump($a);
$a = -123; // a negative number
var_dump($a);
$a = 0123; // octal number (equivalent to 83 decimal)
var_dump($a);
$a = 0x1A; // hexadecimal number (equivalent to 26 decimal)
var_dump($a);
$a = 0b11; // binary number (equivalent to 3 decimal)
var_dump($a);
?>Interpreting the code above:
int(1234)
int(-123)
int(83)
int(26)
int(3)Range of an Integer in PHP (Integer Overflow)
If PHP encounters a number outside the limits of an integer, it will be interpreted as a float instead of an integer.
Example: Integer Overflow on 32-bit Systems in PHP
<?php
$large_number = 2147483647;
var_dump($large_number);
$large_number = 2147483648;
var_dump($large_number);
?>Interpreting the code above:
int(2147483647)
float(2147483648)Example: Integer Overflow on 64-bit Systems in PHP
<?php
$large_number = 9223372036854775807;
var_dump($large_number);
$large_number = 9223372036854775808;
var_dump($large_number);
?>Interpreting the code above:
int(9223372036854775807)
float(9.2233720368548E+18)How to use it in a control structure?
<?php
// it is not necessary to perform the comparison against a boolean type
if ($truth == TRUE) {
echo "this is true\n";
}
// because it can be written like this
if ($truth) {
echo "this is true\n";
}
?>Interpreting the code above:
this is true this is trueFloat in PHP
A float or floating-point number is a signed number with a decimal part; the same rule applies for PHP.
Notations for Floating-Point Numbers in PHP
Example of Floating-Point Numbers
<?php
$a = 1.234;
var_dump($a);
$b = 1.2e3;
var_dump($b);
$c = 7E-10;
var_dump($c);
?>Interpreting the code above:
float(1.234)
float(1200)
float(7.0E-10)Range of Floating-Point Numbers
The size of a float depends on the platform, although a common value consists of a maximum of ~1.8e308 with a precision of approximately 14 decimal digits (which is a 64-bit value in IEEE format).
NULL in PHP
The NULL value indicates that the variable assigned that value has no value assigned; that is, it indicates that the variable has no value whatsoever.
The variable is considered NULL when:
- The constant NULL has been assigned to it.
- No value has been assigned to it.
- Or it has simply been destroyed with the unset() method.
Type Juggling (Type Conversion)
In this entry, we will talk a little about type conversion in PHP when performing different operations, such as mathematical ones.
PHP is not a strongly typed language, which means that it does not control the data types of variables, and if you want to perform operations, PHP performs a type conversion according to the operation you want to perform; for the following example:
$string1 = "8";
$string2 = "4cuatro";
$stringFinal = $string1 + $string2;
echo "Vamos a sumar $string1 + $string2 <br>";
echo "resultado $stringFinal";It gives the following output:
We are going to add 8 + 4four
result 12 When trying to perform an addition operation, the PHP interpreter automatically converts the text contained in the variable $string1 from "8" to 8. A similar behavior happens with the variable $string2; the interpreter converts to a numerical value until it finds the first character "c", giving an implicit conversion of the value 4 to perform the addition operation, and both values are summed.
If, on the contrary, we apply the following example:
$string1 = "8";
$string2 = "c4uatro";
$stringFinal = $string1 + $string2;
echo "Vamos a sumar $string1 + $string2 <br>";
echo "resultado $stringFinal";We are going to add 8 + c4four
result 8 The interpreter again converts $string1 from "8" to 8, but for the value stored in the variable $string2, the interpreter detects that the first character is not numeric, being "c", and therefore there is nothing to convert, and the variable is evaluated by default as zero.
Other Aspects of the NULL Data Type
The constant NULL is case-insensitive.
Concatenation in PHP
Concatenation in PHP is done with the dot (.), not with the + as in other languages:
echo "Hello " . $name;This works to join strings. If you want to include variables directly inside a string, you can use double quotes:
echo "Hello $name"; // prints Hello AndrésWith single quotes, the content is taken as literal text:
echo 'Hello $name'; // prints Hello $nameThis is useful when you want to print something without PHP interpreting it as a variable.
Operations with Variables
You can perform arithmetic operations according to the data type.
Concatenation only works with strings; other types may require conversion.
Booleans, integers, and floats behave according to their type.
Examples:
$numero = 10;
$decimal = 10.5;
$esValido = true;
echo $numero + 5; // 15
echo $decimal + 4.5; // 15
echo $esValido ? 'Sí' : 'No'; // YesSingle quotes for literal text.
This serves as a basis for understanding how variables work in PHP and practicing their use before moving on to functions, classes, and other more advanced structures.
echo 'Hello '. $name. ' Hello';
echo "Hello $name Hello";Summary
Variables begin with $.
- They cannot contain spaces or start with numbers.
- Use camel case or snake case for readability.
- Data types are optional, but recommended.
- Concatenation with . or interpolation with double quotes.
Functions
Now let's move on to functions in PHP. How on earth can we implement functions in PHP?
Before that, let's recall the basic concept: functions exist to reuse code.
For example, even though we have seen practically nothing, suppose this is crucial or very important to you, and you want to print it in two parts: one in the header and another in a menu.
So, how would you do it as we have shown up to this point? You would have to duplicate it in those crucial parts. As I mentioned before: open the PHP block here, print the code, then open another block there, print it again... which is obviously a problem.
Imagine that it is more code, that it includes connecting to the database, validations, or that it simply changes in the future. Clearly, this is impractical.
That is why functions arise, which exist in practically every programming language. They are a key piece for modularization, organization, code simplification, and the creation of reusable components.
Creating our first function
Having clarified this, I am going to create a new file so as not to mix so many things. In this case, I called it functions.php.
To declare a function in PHP, just like before, we open the PHP block:
<?php ?>And now, yes, we create our first function:
function hello() {
echo "Hi";
}This is the basic structure:
- The reserved word function.
- The name of the function (no spaces or special characters).
- The parentheses.
The curly braces that contain the reusable code.
As a note: you cannot use reserved names as variables (although in PHP you can use $function because all variables have $, but not in other languages).
If you try to call a function that does not exist, you will get an error. But as long as it is only declared and not invoked, nothing will happen.
To invoke it, you simply do:
hello();Using Parameters
Now let's move on to another important part: parameters.
Let's design a function that receives a name:
function hello($name) { echo "Hello " . $name; }If you call it without parameters, PHP will indicate that the function expected one, but received zero.
To use it correctly:
hello("Andrés");Parameters simply represent the data that the function needs to execute its purpose.
A Function with Multiple Parameters
Now suppose a sum function:
function sum($a, $b) {
echo $a + $b;
}We call it like this:
sum(5, 10);Up to this point, it prints the result, but does not return anything. This becomes problematic when we want to use the calculated value outside the function.
Returning Values
If we want the function to “return” something to be reused, we use return:
function sum($a, $b) {
return $a + $b;
}Now we can do:
$result = sum(5, 10);
var_dump($result);This returns the type and value to you, thanks to var_dump.
Data Types in Arguments
Another important detail: if you do not declare types, PHP will try to convert the values automatically, which can generate silent errors.
For example, you could pass a string where a number was expected.
To avoid this, you can type like this:
function sum(int $a, int $b) {
return $a + $b;
}If you call:
sum("hello", 5);Now the error will be clear: the argument does not meet the type.
You can also allow multiple types:
function sum(int|float $a, int|float $b) {
return $a + $b;
}Declaring the Return Type
In addition to the type of the arguments, you can also type the value that the function will return:
function sum(int $a, int $b): int {
return $a + $b;
}This provides more consistency and security to the code.
If the function were to return strings, for example, you would simply indicate : string.
Other Useful Aspects
PHP also supports:
- variadic functions (function test(...$args)),
- arrow functions (fn($a) => $a * 2),
- and many internal functions like var_dump, gettype, etc.
- In general, with this you already have:
- How to declare functions,
- How to invoke them,
- How to use parameters,
- How to return values,
- How to use data types in parameters and returns.
🧠 Control Structures: The Use of Conditionals
1. Basic Concept: What is a Conditional?
A conditional is simply a control structure that allows making decisions based on a boolean condition (true or false). It is the equivalent of the if and else structures that exist in most programming languages.
Example: Is your age greater than 18? (True or False).
2. Comparison Operators
To establish a condition, we use comparison operators:
Strict equality (==): Compares if two values are equal. (Different from simple assignment: $age = 18;).
- Greater than (>): $age > 18
- Less than (<): $age < 18
- Greater than or equal to (>=): $age >= 18
- Less than or equal to (<=): $age <= 18
- Not equal to (!= or <>)
Practical Example: Age Validation
Let's consider the validation of the age of majority, which in many places is from 18 years old.
<?php
$age = 18;
// We use the "Greater than or equal to" operator (>=) to include 18
if ($age >= 18) {
echo "You are an adult. Congratulations, now you have to work.";
} else {
echo "You are a minor.";
}
?>- Problem with only > (Greater than): If we use $age > 18, the code will fail if the age is exactly 18, because 18 is not greater than 18.
- Solution: The >= operator solves this by comparing whether it is greater than or exactly equal to the specified value.
Nesting Conditions: elseif
When we have multiple conditions that are mutually exclusive (that is, we only want one of them to be met), we must nest the code using elseif.
If we do not nest the conditionals, all blocks whose condition is met will be executed, which is incorrect for most logic (such as determining a grade range).
🎓 Grade Example (Exclusive Logic)
We want to evaluate if a person is excellent, good, or needs improvement, based on ranges:
- Excellent: Greater than or equal to 90.
- Good: Greater than or equal to 70.
- Needs Improvement: Less than 70.
<?php
$grade = 75;
if ($grade >= 90) {
echo "You are excellent."; // If it enters here, it ignores the rest
} elseif ($grade >= 70) {
echo "You are good. An average like everything in your life."; // If it enters here, it ignores the 'else'
} elseif ($grade >= 50) {
echo "You need to improve.";
} else {
echo "You are a 'zapacuco'."; // If none of the above conditions were met
}
?>Advantage of elseif: PHP evaluates the first if. If it is true, it executes the block and exits the entire structure. If it is false, it moves to the next elseif and repeats the process. This ensures that only a single block of code is executed, guaranteeing the correct logic.
Example with 75:
- $nota >= 90 (75 >= 90) - False.
- elseif ($nota >= 70) (75 >= 70) - True. - Executes and exits.
⚙️ Control Structures: The use of switch
The switch is another control structure that, while similar to if/else, offers a cleaner and more appropriate implementation for evaluating multiple cases.
1. ❓ The Problem of Multiple Conditions
Although if/else works for any evaluation, its readability becomes complicated when four, five, or more nested or sequential conditions are needed.
For example, if we needed to evaluate the nota variable with multiple ranges (greater than 90, greater than 80, greater than 70, etc.), the chain of else if becomes dense:
if ($grade > 90) {
// ...
} else if ($grade > 80) {
// ...
} else if ($grade > 70) {
// ...
}
// ... and so on.For these scenarios, the switch is a more suitable and easier-to-read alternative.
2. 📝 Basic switch Syntax
The switch structure evaluates a single expression (variable, function return, etc.) against a series of predefined cases (case).
switch ($condition_to_evaluate) {
case $value1:
// Code to execute if value1 is met
break;
case $value2:
// Code to execute if value2 is met
break;
// ... more cases
default:
// Code to execute if no case is met
break;
}Key Elements:
- switch (condition): This is where the variable or value we want to evaluate is placed (e.g., grade, day).
- case value:: Defines a specific condition. Note that a colon : is used instead of curly braces {}.
- break;: Essential. Just as else prevents unnecessary re-evaluation in the if/else structure, the break ensures that, once a case is met, the program stops evaluating the subsequent cases and immediately exits the switch.
- If you remove the break, the program will execute the code for that case and continue executing the code for the next case until it finds a break or finishes the structure.
3. 🎯 The Default Case (default)
The default is the equivalent of else in the if/else structure.
- Function: If none of the case conditions are met, the code block within default will always execute.
- Location: By convention, it is always placed as the last case to evaluate.
- Use: You can use it to handle unexpected values (e.g., if you expect a day of the week, but the user enters "X") or to define a base action if the value does not match any specific case.
Practical Example (Days of the Week)
If we want to evaluate the variable day, a switch is perfect for the seven days.
<?php
$day = "Monday";
switch ($day) {
case 'Monday':
echo "The week begins."; // Enters here
break;
case 'Friday':
echo "Last working day.";
break;
default:
echo "It's a normal day."; // Enters if the day is 'Tuesday', 'W', etc.
// The break here is optional, as it is the last case.
break;
}
?>Reminder: The case conditions are evaluated in the order they are arranged. It is crucial that the order makes sense for your application's logic.
4. 🚀 Practice Tips
To familiarize yourself with the switch, I recommend:
- Think about the Logic: Create a business scenario (e.g., handling order statuses, assigning categories to scores).
- Implement the switch: Write the structure for that scenario.
- Convert and Compare: Use AI tools (like your editor's code assistant) to convert your switch to an if/else and vice versa. This will help you understand how the two structures are mapped: the default will always be the final else.
Ternary Operator?: - Coalescing?? and Null Safety
We're going to explore two very useful operators in PHP for performing short conditional statements and handling value assignment, especially when it comes to avoiding null types.
The two operators we'll look at are:
- Ternary Operator (? :)
- Null Merge Operator (Null Coalescing Operator, ??)
1. Ternary Operator (? :)
The ternary operator is the most concise way to replace a simple if-else structure that assigns a value to a variable.
We start with the previous conditional:
$age = 5;
$older = false; // It is initialized to avoid nulls
if ($age >= 18) {
$older = true;
} else {
$older = false;
}condition ? value_if_true : value_if_false - If the condition is true, it assigns the first value; otherwise, it assigns the second.
And the ternary operator looks like:
$age = 20; $older = ($age >= 18) ? true : false;The main advantage is that it allows for clean assignments without the need to initialize the variable before or use multiple lines of code.
2. The Null Coalescing Operator (??)
This operator (also known as the Null Coalescing Operator) is used to check if a variable or expression is null and, if so, assign it a default value. It is very useful for handling user input data (like forms) and ensuring there is always a defined value.
variable ?? default_value - If variable is not null, use its value. If variable is null, use default_value.
/**
* Demonstrating the Null Coalescing Operator (??)
* This operator returns its first operand if it exists and is not NULL;
* otherwise it returns its second operand.
*/
$userValue = null;
$defaultValue = 10;
// Scenario 1: $userValue IS null
// Check if $userValue is non-null. Since it IS null, $defaultValue (10) is assigned.
$result = $userValue ?? $defaultValue;
echo "Scenario 1 (null input):" . "<br>";
echo "\$userValue is: " . var_export($userValue, true) . "<br>";
echo "\$defaultValue is: $defaultValue" . "<br>";
echo "\$result = \$userValue ?? \$defaultValue; -> Result: **$result**" . "<br>";
echo "<hr>";
// Scenario 2: $userValue is NOT null
$userValue = 50;
$defaultValue = 10;
// Check if $userValue is non-null. Since it IS 50 (not null), 50 is assigned.
$result = $userValue ?? $defaultValue;
echo "Scenario 2 (non-null input):" . "<br>";
echo "\$userValue is: $userValue" . "<br>";
echo "\$defaultValue is: $defaultValue" . "<br>";
echo "\$result = \$userValue ?? \$defaultValue; -> Result: **$result**" . "<br>";The Importance of Avoiding Nulls (Null Safety)
The use of operators like ?? is closely linked to the concept of **Null Safety** in programming.
In many languages (like JavaScript), attempting to access a method or property of a variable that is null or undefined causes a fatal error (an exception).
Although in PHP some string functionalities are handled using helper functions (str_lower() instead of $string->toLowerCase()), the ?? is essential to avoid ambiguity and errors that arise when working with null references in the application's flow. It ensures that the variable will always have a value to work with.
Challenges
🔹 1. Function that says whether a number is even or odd
Create a function that receives a number and returns "Even" or "Odd".
You must implement it using conditionals AND with the ternary operator (?:)
Challenge Resolution:
With Conditionals
/**
* Checks if a number is even or odd using a standard if-else structure.
*
* @param mixed $number The value to check.
* @return string The result of the check or an error message.
*/
function isEvenOrOdd($number) {
// 1. Data Validation: Ensure the input value is numeric.
if (!is_numeric($number)) {
return "The entered value is not a number.";
}
// 2. Conditional Check using the Modulo Operator (%).
// If the remainder of the division by 2 is 0, the number is even.
if ($number % 2 === 0) {
return "The number $number is even.";
}
// Otherwise, the number must be odd.
else {
return "The number $number is odd.";
}
}We use it:
echo isEvenOrOdd(10) . "<br>"; // 10 is even. echo esParOImpar(7) . "<br>"; // 7 is odd. echo isEvenOrOdd("ABC") . "<br>"; // Not a number.With Ternaries
This is the implementation with the ternaries:
/**
* Checks if a number is even or odd using the ternary operator.
*
* @param mixed $number The value to check.
* @return string The result of the check or an error message.
*/
function isEvenOrOddTernary($number) {
// 1. Input Validation: Ensure the value is a number.
if (!is_numeric($number)) {
return "The entered value is not a number.";
}
// 2. Main Logic: Use the ternary operator to determine if it is even or odd.
// The expression ($number % 2 === 0) checks if the remainder of the number divided by 2 is 0.
$res = ($number % 2 === 0)
? "The number $number is even." // Value if TRUE (EVEN)
: "The number $number is odd."; // Value if FALSE (ODD)
// 3. Return the result.
return $res;
/*
* OPTIONAL: The function can be simplified by removing the intermediate variable $res
* and returning the ternary result directly:
*
* return ($number % 2 === 0)
* ? "The number $number is even."
* : "The number $number is odd.";
*/
}💡 Extra: Arrow Functions (fn)
Taking advantage of the single-line simplification, we can refactor the function using an **Arrow Function (fn)**, a PHP feature for functions defined in a single statement.
The arrow function is a concise form of representation. By definition, it always returns the value of the expression placed after the arrow, without the need to use the return keyword.
/**
* Checks if a number is even or odd using the Arrow Function syntax.
* * This format is concise and only allows a single expression.
*
* @param int $number The numeric value to check.
* @return string The result of the check.
*/
// The 'fn(parameters) => expression' syntax performs an implicit 'return' of the expression.
$arrowFunction = fn($number) =>
($number % 2 === 0)
? "The number $number is even." // Value returned if EVEN
: "The number $number is odd."; // Value returned if ODD
// Usage: The variable ($arrowFunction) is called as if it were the function.
echo $arrowFunction(12) . "<br>";
// Output: The number 12 is even.<br>
echo $arrowFunction(7);
// Output: The number 7 is odd.Note on Typing: In modern versions of PHP, it is recommended to add type signatures (arguments and returns) for greater robustness and to dispense with manual validations like is_numeric().
/**
* Checks if a number is even or odd, enforcing argument and return types.
* * @param int $number The number to check.
* @return string The result of the check.
*/
// The ': string' ensures the function must return a string.
// The 'int $number' ensures the input must be an integer.
function isEvenOrOddTyped(int $number): string {
// If you pass a value that is not an integer (like a string),
// PHP will throw a TypeError at the function call (this is good practice).
// Ternary operator logic remains the same.
return ($number % 2 === 0)
? "The number $number is even."
: "The number $number is odd.";
}
// Usage Example:
echo isEvenOrOddTyped(42) . "<br>";
// Output: The number 42 is even.
// Example of how it enforces typing (would throw an error if uncommented
// and strict types were enabled):
// echo isEvenOrOddTyped("hello"); // This would cause a fatal TypeError
// if 'declare(strict_types=1);' was used.Another implementation:
$parOImparFlecha = fn(int $numero) : string => ($numero % 2 == 0) ? "The number $numero is EVEN." : "The number $numero is ODD.";🔹 2. Function that calculates the final price with discount
The function receives a price and a discount percentage.
It must return the final price AND a message indicating the applied Discount:
- Invalid Price, if the price is NOT a number or is negative
- Invalid Discount (must be between 0 and 100), if the discount is greater than 100, negative, or not a number
- Price without discount:, If the discount is 0
- Free Product, if the discount is 100
- Price with discount, for all other cases
The implementation must be done with conditionals and also with switch
Challenge Resolution:
We define the function and start by validating data integrity. It's a good practice to stop execution as soon as an invalid value is detected.
function calcularPrecioFinal($precio, $descuento): string {
// 1. PRICE VALIDATION (Invalid or Negative)
// We use OR (||) because if ANY of the conditions is met, it's an error.
if (!is_numeric($precio) || $precio < 0) {
return "ERROR: Invalid or negative price entered.";
}
// 2. DISCOUNT VALIDATION (Invalid or Out of Range 0-100%)
if (!is_numeric($descuento) || $descuento < 0 || $descuento > 100) {
return "ERROR: Invalid discount. Must be between 0% and 100%.";
}
// Note on typing: If the function signature includes types (e.g., (float $precio, int $descuento): string),
// the is_numeric() check can be omitted.
// Price formatting for output (e.g., $10.00)
$precioFormateado = number_format($precio, 2);
// 3. SPECIAL CASE: 0% Discount
if ($descuento == 0) {
return "Full price. No discount. Total: $precioFormateado.";
}
// 4. SPECIAL CASE: 100% Discount
if ($descuento == 100) {
return "The product is FREE! Total: $0.00.";
}
// 5. GENERAL CASE: Valid Discount (between 1% and 99%)
// If execution reaches this point, we don't need further checks (it's not invalid, not 0%, not 100%).
// Final price calculation:
// a) Calculate the discount percentage: $descuento / 100 (e.g., 50 / 100 = 0.5)
// b) Multiply by the price to get the discount amount: $precio * 0.5 = $25.00
// c) Subtract that amount from the base price.
$precioFinal = $precio - ($precio * ($descuento / 100));
$precioFinalFormateado = number_format($precioFinal, 2);
return "Price with a $descuento% discount. Total: $precioFinalFormateado.";
}Once the data is valid (numeric and within an acceptable range), we proceed to evaluate the special cases (0% and 100%).
// 3. SPECIAL CASE: 0% Discount
if ($descuento == 0) {
return "Full price. No discount. Total: $precioFormateado.";
}
// 4. SPECIAL CASE: 100% Discount
if ($descuento == 100) {
return "The product is FREE! Total: $0.00.";
}
// 5. GENERAL CASE: Valid Discount (between 1% and 99%)
// If execution reaches this point, we don't need further checks (it's not invalid, not 0%, not 100%).
// Final price calculation:
// a) Calculate the discount percentage: $descuento / 100 (e.g., 50 / 100 = 0.5)
// b) Multiply by the price to get the discount amount: $precio * 0.5 = $25.00
// c) Subtract that amount from the base price.
$precioFinal = $precio - ($precio * ($descuento / 100));
$precioFinalFormateado = number_format($precioFinal, 2);
return "Price with a $descuento% discount. Total: $precioFinalFormateado.";
}Let's test different scenarios:
echo calcularPrecioFinal(50, 0) . "<br>"; // No discount: $50.00
echo calcularPrecioFinal(100, 25) . "<br>"; // Normal discount: $75.00
echo calcularPrecioFinal(80, 100) . "<br>"; // Free: $0.00
echo calcularPrecioFinal(10, -5) . "<br>"; // ERROR: Invalid discount.
echo calcularPrecioFinal("ABC", 25) . "<br>";// ERROR: Invalid price.💡 Note on the Use of return
In this function, the else structure is not used because each condition that handles a specific business case uses the keyword return.
When a function encounters a return, execution terminates immediately, regardless of the code that follows.
- If the function enters the if for invalid price, it returns the error and does not execute the rest of the code.
- If the function enters the if for 0% discount, it returns the full price and does not execute the final calculation code.
This avoids nesting multiple if/else statements and makes the logic flow flat and easy to follow.
🏗️ The Nightmare of Forms in PHP
Now, the next step is where things get a bit ugly. We're going to start working with forms. And why do I say it gets ugly? Because this is one of the things that annoys me the most about PHP: making a form in pure PHP can lead to many problems if the code is not organized well.
It's very easy to end up with spaghetti code, a bunch of messy files that immediately cause errors. However, it is equally important to know how it works, even if it is cumbersome.
📝 Basic Elements of an HTML Form
It all starts with a normal form. A form with its action and its method.
GET Method
By convention (good practices), we use GET requests for queries.
- Risk: You shouldn't (although technically you can) use GET to create users or send sensitive data, such as credit cards.
Reason: Everything travels in the URL, which is extremely insecure due to the multiple vulnerabilities that can be exploited (something I will explain to you little by little throughout this course).
POST Method
The POST request type is more secure.
- Difference: It no longer travels directly in the URL, but as a request body (something called the body).
- Viewing: This can be seen in the browser by opening the Developer Tools (F12) and checking the Network section (which is very useful for my own developments).
Action and Form Fields
The action (who wants to process it) is where things start to get annoying in PHP: it can be the same file or another file you want to reference.
In this case, we'll use a POST request type to simulate a simple contact form: name, surname, email, and a message.
- Fields: A normal text field, an input (type text, email, etc.) or a textarea for the message is used.
- Required HTML: It's vital to know HTML and JavaScript, so I assume you have that knowledge. You can search for "HTML forms" on Google if you don't.
- Name (name): It is extremely important to assign it a name, as this is how you will reference it from PHP.
- placeholder: It's a label that appears inside the input. Usually, for good practice, a label tag is also included, but I don't want to complicate the exercise.
- type="email": The validations offered by the browser for email type fields are excellent; anything free is appreciated.
- textarea: Used for the content of the message (a large text field) so the user can express themselves freely.
The form looks like this:
04_formularios.php
<form action="04_forms.php" method="POST">
<input
type="text"
name="name"
placeholder="Name"
value=""
style="width: 100%; margin-top: 5px; padding: 8px; border: 1px solid #ccc;"
>
<input
type="text"
name="surname"
placeholder="Last Name"
value=""
style="width: 100%; margin-top: 5px; padding: 8px; border: 1px solid #ccc;"
>
<input
type="email"
name="email"
placeholder="Email"
value=""
style="width: 100%; margin-top: 5px; padding: 8px; border: 1px solid #ccc;"
>
<textarea
name="message"
placeholder="Message"
style="width: 100%; margin-top: 5px; margin-bottom: 5px; min-height: 100px; padding: 8px; border: 1px solid #ccc;"
></textarea>
<div style="display: flex; justify-content: flex-end;">
<button
type="submit"
style="
background-color: green;
color: white;
padding: 10px 15px;
border: none;
cursor: pointer;
font-weight: bold;
"
>
Send
</button>
</div>
</form>Processing data in PHP
To process the data, we use PHP and the $_POST array:
04_formularios.php
$all_values = [
'name' => $_POST['name'] ?? '',
'surname' => $_POST['surname'] ?? '',
'email' => $_POST['email'] ?? '',
'message' => $_POST['message'] ?? ''
];- We use $_POST. This syntax ($) indicates that it is an internal PHP element, and in this case, $_POST refers to the POST method that we defined in the HTML form.
- For example, $_POST['name'] accesses the value sent from the form.
- If the request was configured by GET in the form:
- <form action="04_formularios.php" method="GET">
- It would be $_GET['name'] instead.
- The ?? '' operator prevents null values if the user didn't send anything.
- Remember that name, surname, etc., must match the names of the HTML inputs.
The first thing I find awful is that one of the ways of working in PHP is to process everything in the same file. This inevitably leads to spaghetti code, since if it's a contact form, you'll likely want to save the data in the database, which would involve making the connection and the process right there.
Arrays in PHP are similar to other programming languages. We declare a variable and use square brackets ([]) to indicate that it is an array.
Data Visualization
To test our form, we can use print_r() or var_dump() in PHP, which allows us to see the structure of the data sent:
echo '<pre>';
print_r($all_values);
echo '</pre>';
var_dump($all_values);This is useful for debugging and initial testing.
Remember that data sent by GET will appear in the URL, while data sent by POST will not.
😩 The Complication of Manually Processing a Form
The problem is that, apart from the enormous freedom, the code we are going to implement is a bit complicated and difficult to read as we include all these functionalities:
- Validations.
- Database injection.
- To demonstrate a problem, if a user enters malicious code, for example: script alert('Hacked!') /script
- The errors will be displayed on the screen:
- Solution: To sanitize user data, we will use the htmlspecialchars() function. This converts special HTML characters into entities, preventing injected code from running.
- Error handling.
- Returning the previous value (notice that, upon reloading, the previous value is lost, which shouldn't happen).
🍝 The problem of "Spaghetti" code in PHP forms
We left off at this form and, as you can see, we are already starting to have problems. Everything is in the same file: the PHP logic mixed with the HTML. We haven't even connected the database, added validations, or error handling yet, and the file already feels heavy.
Although we could try to make it modular by creating folders and files, here lies the big problem with native PHP: it is so open that every programmer can organize the project however they want. What is logical for one person isn't for another. If two or three people work on a project like this, the folder structure becomes madness.
To avoid this "debauchery" in organization, frameworks exist. Not only do they provide us with ready-to-use tools, but they also impose the foundations to keep the application organized and scalable.
🔌 Connection and Registration Logic
I asked Gemini for help in structuring an example of how this implementation would look in a "traditional" (and cumbersome) way. Here is a summary of what happens in the code:
- PDO Connection: We establish the connection using the host, user (root by default), and password. We use a try-catch block so that if the connection fails, the application doesn't "explode" and we can control the error.
- Validation and Sanitization: We use trim() to clean up whitespace and check if the fields are empty or if the email is valid.
- Data Insertion: We write the SQL INSERT INTO statement. A good practice is to use parameters (like :name, :email) instead of inserting variables directly, to avoid SQL injection attacks.
🔒 Security and Special Characters
Something vital is to prevent malicious code from being injected (like a JavaScript alert()). To do this, we use the htmlspecialchars() function. This function "escapes" special characters (like the < > signs) so that the browser reads them as plain text and not as executable code.
// Protection example echo htmlspecialchars($user_input, ENT_QUOTES, 'UTF-8');The code looks like:
04_formularios.php
<?php
// Configuración de la base de datos
$host = 'localhost';
$db_name = 'contacto_db';
$user = 'root'; // Cambia según tu config
$password = ''; // Cambia según tu config
$errors = [];
$success_message = "";
// 1. Conexión a la base de datos con PDO
try {
$pdo = new PDO("mysql:host=$host;dbname=$db_name;charset=utf8", $user, $password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
die("Error de conexión: " . $e->getMessage());
}
// 2. Procesar el formulario cuando se envía (POST)
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// Recoger y limpiar valores previos
$name = trim($_POST['name'] ?? '');
$surname = trim($_POST['surname'] ?? '');
$email = trim($_POST['email'] ?? '');
$message = trim($_POST['message'] ?? '');
// 3. Validaciones
if (empty($name)) $errors['name'] = "El nombre es obligatorio.";
if (empty($surname)) $errors['surname'] = "El apellido es obligatorio.";
if (empty($email)) {
$errors['email'] = "El email es obligatorio.";
} elseif (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
$errors['email'] = "El formato de email no es válido.";
}
if (empty($message)) $errors['message'] = "El mensaje no puede estar vacío.";
// 4. Si no hay errores, insertar en la BD
if (empty($errors)) {
try {
$sql = "INSERT INTO mensajes (nombre, apellido, email, mensaje) VALUES (:n, :s, :e, :m)";
$stmt = $pdo->prepare($sql);
$stmt->execute([
':n' => $name,
':s' => $surname,
':e' => $email,
':m' => $message
]);
$success_message = "¡Mensaje enviado y guardado correctamente!";
// Limpiar campos después de éxito
$name = $surname = $email = $message = "";
} catch (PDOException $e) {
$errors['db'] = "Error al guardar en la base de datos: " . $e->getMessage();
}
}
}
?>
<?php if ($success_message): ?>
<div style="background-color: #d4edda; color: #155724; padding: 10px; margin-bottom: 10px; border: 1px solid #c3e6cb;">
<?php echo $success_message; ?>
</div>
<?php endif; ?>
<form action="" method="POST">
<input
type="text"
name="name"
placeholder="Nombre"
value="<?php echo htmlspecialchars($name ?? ''); ?>"
style="width: 100%; margin-top: 5px; padding: 8px; border: 1px solid <?php echo isset($errors['name']) ? 'red' : '#ccc'; ?>;"
>
<?php if(isset($errors['name'])): ?> <small style="color:red;"><?php echo $errors['name']; ?></small> <?php endif; ?>
<input
type="text"
name="surname"
placeholder="Apellido"
value="<?php echo htmlspecialchars($surname ?? ''); ?>"
style="width: 100%; margin-top: 5px; padding: 8px; border: 1px solid <?php echo isset($errors['surname']) ? 'red' : '#ccc'; ?>;"
>
<?php if(isset($errors['surname'])): ?> <small style="color:red;"><?php echo $errors['surname']; ?></small> <?php endif; ?>
<input
type="email"
name="email"
placeholder="Email"
value="<?php echo htmlspecialchars($email ?? ''); ?>"
style="width: 100%; margin-top: 5px; padding: 8px; border: 1px solid <?php echo isset($errors['email']) ? 'red' : '#ccc'; ?>;"
>
<?php if(isset($errors['email'])): ?> <small style="color:red;"><?php echo $errors['email']; ?></small> <?php endif; ?>
<textarea
name="message"
placeholder="Mensaje"
style="width: 100%; margin-top: 5px; margin-bottom: 5px; min-height: 100px; padding: 8px; border: 1px solid <?php echo isset($errors['message']) ? 'red' : '#ccc'; ?>;"
><?php echo htmlspecialchars($message ?? ''); ?></textarea>
<?php if(isset($errors['message'])): ?> <small style="color:red;"><?php echo $errors['message']; ?></small> <br> <?php endif; ?>
<div style="display: flex; justify-content: flex-end; margin-top: 10px;">
<button
type="submit"
style="background-color: green; color: white; padding: 10px 15px; border: none; cursor: pointer; font-weight: bold;"
>
Enviar
</button>
</div>
</form>⚠️ Conclusion: The first-time programmer's nightmare
As you can see, this file has become an "all-in-one": connection, sanitization, validation, insertion, success messages, errors, and the HTML form. This is the definition of spaghetti programming.
For a beginning programmer, this can be frustrating. You might think: "If this is this difficult, a framework will be worse." But it's quite the opposite. Frameworks abstract all this complexity. In the following videos, I will show you how a framework makes this whole process much cleaner, safer, and, above all, faster.
Would you like me to show you a direct comparison of this same code written in a framework in the next class so you can see how many lines of code we can save?
🛠️ Necessary tools: Database and SQL
Before we dive deep into the code, let's talk about infrastructure. If you are not using tools like XAMPP or WAMP, you will need to manage your database manually.
- DBngin (Mac/Windows): It is an excellent program for setting up MySQL or PostgreSQL services easily. You just have to add a new service and follow the wizard.
- TablePlus: I recommend it for managing your tables visually. It is compatible with Windows, Mac, and Linux.
- SQL: For this to work, we must run an SQL script that creates our table (for example, messages). If you don't know SQL, don't worry, it's the language we use to talk to the database. Typical acronyms like XAMPP stand for: Apache, MySQL, and PHP.
🛠️ Form Implementation and Refactoring
I have used the Gemini assistant to separate the connection into a separate file called conexion.php. This is vital because, in "vanilla" PHP, you will want to reuse that same connection in multiple parts of the project without having to constantly copy the code.
The Risk of “Reinventing the Wheel”
However, manual modularization has its risks:
- Inconsistency: If you leave the project for four weeks and come back, you will probably structure the new modules differently than the previous ones.
- Security and Visibility: When importing files with require, all variables (such as the host or password) are exposed. If I print the $host variable in the HTML, it will be displayed without issues, and that is something we should protect.
- Fragility: If someone decides to change the name of the connection variable (for example, from $pdo to $connect), the application will stop working everywhere it is used, generating exceptions that are difficult to track.
This is why I insist: it makes no sense to reinvent the wheel. Frameworks already offer excellent organization and solve critical problems that we haven't even touched on here, such as protection against CSRF tokens.
By using a framework, you don't waste time defining a structure from scratch or creating manual validations for each field. Pure PHP is very prone to generating "spaghetti code" where business logic and HTML are mixed in a flawed way.
Closing ?> PHP files
Even if we separate the logic into a 04_formularios_logic.php file, you will notice something curious: in files that are purely PHP, the closing tag ?> is often not used. This is done to prevent accidental white spaces at the end of the file from causing errors with the page headers:
conexion.php
<?php
$host = 'localhost';
$db_name = 'contacto_db';
$user = 'root';
$password = '';
try {
$pdo = new PDO("mysql:host=$host;dbname=$db_name;charset=utf8", $user, $password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
die("Error de conexión: " . $e->getMessage());
}04_formularios_logic.php
<?php
$errors = [];
$success_message = "";
// 2. Procesar el formulario cuando se envía (POST)
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
***
}04_formularios.php
<?php
require_once 'conexion.php';
require_once '04_formularios_logic.php';
?>
<form action="" method="POST">
***
</form>PHP Classes: Constructors and Properties, Inheritance, Abstract Classes
🏗️ What is a Class?
You have surely heard that PHP is an object-oriented language. Although it sounds abstract at first, classes are small "gems" that allow for modularization. Thanks to them, we can avoid the code clutter often seen in simple form scripts.
Comparison with Frameworks
If we look at a project in Laravel, we will see that classes are everywhere: controllers, models, service providers, etc. Everything relies on this structure; you can visit any of my GitHub repositories and see the Laravel and CodeIgniter projects.
In my free development application: my blog, my academy, and others. Everything is built in Laravel and, as I mentioned at the beginning, everything relies on PHP. Object-oriented programming, based on classes, is used extensively here.
Object-Oriented Programming: A Key Idea
The third thing I want to tell you is that surely, when you are starting in programming, people always mention that languages like PHP are object-oriented, and at that point, it sounds abstract or confusing. But believe me, this has a lot of power because everything is built from there.
For me, the best thing that exists in programming (besides conditionals, and I say that sarcastically) is the use of classes. They are a small gem, the key piece of modularization, and thanks to that we can advance effectively and avoid disasters like the forms we made before, which surely left you with a bad impression.
Definition of a Class
To define a class, we use the reserved word class. By convention, the name of the class should always start with a capital letter (PascalCase) and be in the singular.
05_clases.php
class Persona {
// Propiedades
public $nombre;
public $edad;
// Constructor: se ejecuta al crear la instancia
public function __construct($nombre, $edad) {
$this->nombre = $nombre;
$this->edad = $edad;
}
// Método: una acción que realiza la clase
public function saludar() {
return "Hola, mi nombre es $this->nombre y tengo $this->edad años.";
}
}- Inside the class, we have a constructor, which I will explain better later. In this example, we are going to define two basic elements: name and age. It is a simple example, but you could add ID, marital status, last name, height, weight, nationality, etc.
- Then we create a simple function called saludar. This represents an action that the person can perform. There could be many more: eat, walk, work, etc., depending on the purpose of your application.
- Inside the method, we simply print a message like:
“Hello, my name is Pepito and I am so many years old.”- The words public, protected, and private indicate access levels. For now, don't worry too much about that; we will clarify it later.
- When a function is inside a class, it is called a method. When it is outside, it is simply called a function. This is an important convention.
Instances: How to Use a Class
To use this class, we need to create an instance (an object) using the word new. This is where we differentiate: the class is the "mold" (capitalized) and the object is the specific variable (lowercase):
$juan = new Persona("Juan", 25);For example, we are not creating "a person," but specific people: Juan, María, Pedro, etc. Just like with a payment gateway: you don't register a single payment, you register many.
When we use new, the constructor is automatically executed, which receives the parameters necessary to build the instance. This ensures that the class has a valid state from the beginning.
Once the instance is created, we can use its methods, such as saludar.
Properties and Access with $this
Variables inside a class are called properties.
To access them from within the class, we use $this, which is a reference to the instance itself.
From outside the class, we use the arrow -> to access both methods and properties:
return "Hello, my name is $this->nombre and I am $this->edad years old.";It is very similar to working with normal variables, but now everything is organized within a structure.
🔒 Access Levels: Public, Protected, and Private
This defines from where we can see the information:
- Public: Access from anywhere.
- Protected: Access only from the class itself and classes that inherit from it.
- Private: Access only from the class where it was defined.
Don't be overwhelmed if it seems intimidating at first. When working with frameworks, these structures become much friendlier because the system itself guides you on where and how to use them.
🧬 Inheritance: Extending Functionalities
Inheritance allows us to create a class from another to take advantage of its methods and properties. For example, an Employee is a Person, but with additional characteristics like a salary.
To implement this, we use the word extends:
05_clases.php
class Empleado extends Persona {
public $salario;
public function __construct($nombre, $edad, $salario) {
// Llamamos al constructor del padre
parent::__construct($nombre, $edad);
$this->salario = $salario;
}
public function trabajar() {
return "$this->nombre está trabajando por un salario de $this->salario.";
}
}
class Empleado extends Persona {
public function __construct(
string $nombre,
int $edad,
public float $salario
) {
// Llamamos al constructor de Persona
parent::__construct($nombre, $edad);
}
public function trabajar(): string {
$this->saludar();
return "{$this->nombre} está trabajando por un sueldo de {$this->salario}.";
}
}
$empleado = new Empleado("Ana", 30, 2500);
// echo $empleado->saludar(); // Heredado
echo $empleado->trabajar(); // PropioSuppose we have the Persona class, but now we want an Empleado class. An employee is a person, so it would be ideal to reuse what we already have.
For that, we use extends.
- The Empleado class inherits from Persona.
- In the Empleado constructor, we must call the constructor of the parent class (Persona), because it still needs a name and age. This is done with parent::__construct().
- Additionally, we can add specific properties, such as salary, and own methods, such as trabajar.
- Thanks to inheritance, Empleado can use both its own methods and the inherited ones, such as saludar.
In summary:
- Parent Class (Superclass): Persona (has name and age).
- Child Class (Subclass): Empleado (inherits name and age from Persona, but adds "salary").
🏛️ Abstract Classes
An abstract class (using abstract class) is a structure that cannot be instantiated directly. Its only function is to serve as a base for other classes. It is very useful when you want to define a general model (like Citizen) but only want to work with specific implementations (like Resident).
Abstract classes are similar to normal classes, but they cannot be instantiated directly.
Their purpose is to serve as a base for other classes.
For example, a Citizen class can define methods that all child classes must implement, but without saying how. This is useful when you want to force a structure.
An abstract class can have:
- Normal methods (with implementation).
- Abstract methods (without implementation).
If a class has abstract methods, it must be declared as abstract.
Child classes are forced to implement those methods.
05_clases.php
abstract class Ciudadano {
public function __construct(public string $dni) {}
// Obliga a las clases hijas a definir este método
abstract public function obtenerDerechos(): string;
// Método normal que todas las hijas heredarán
public function mostrarIdentidad(): string {
return "Identificación: {$this->dni}";
}
}
class Residente extends Ciudadano {
public function obtenerDerechos(): string {
return "Tiene derecho a voto y salud pública.";
}
}This applies to methods as well as properties and serves to control what can be used from outside and what cannot.
Interfaces
Interfaces are "contracts." They do not contain logic; they only define what methods a class is forced to implement. For example, an Authenticatable interface could force any class that uses it to have a login() method.
Interfaces are similar to abstract classes, but even more restrictive.
- They have no implementation; they only define what methods must exist.
- A class can implement multiple interfaces, which is not possible with direct inheritance.
- Interfaces are useful for defining contracts, for example:
- Authenticatable
- Authorizable
05_clases.php
interface Autenticable {
public function login(): bool;
}
interface Autorizable {
public function verificarPermisos(): array;
}
// Una clase Persona que además es un Usuario del sistema
class Usuario extends Persona implements Autenticable, Autorizable {
public function login(): bool {
// Lógica de inicio de sesión
return true;
}
public function verificarPermisos(): array {
return ['admin', 'editor'];
}
}However, in many practical cases, they are not used as much as inheritance or abstract classes, especially in small projects.
📂 File Importing in PHP: require vs include
If you review applications developed in pure PHP, you will notice several ways to include files. Although in modern frameworks this is handled automatically, it is vital that you know the differences between the traditional methods: require and include.
Key Differences
The syntax for both is equivalent, but their behavior regarding errors is what defines when to use one or the other:
- include: If the file is not found or the path is invalid, PHP throws a Warning. The application will show the notice but will attempt to continue rendering the rest of the page:
<?php include_once 'connection.php'; include_once 'invalid_path_04_forms_logic.php'; ?> *** Warning: include(): Failed opening 'invalid_path_04_forms_logic.php'
- require: If the file is missing, PHP throws a Fatal Error. This stops the execution of the application completely. It is the safest method when the file is critical for the system's operation (such as a database connection):
<?php require_once 'connection.php'; require_once 'invalid_path_04_forms_logic.php'; ?> *** Fatal error: Uncaught Error: Failed opening required 'invalid_path_04_forms_logic.php'
The use of once and loading protection
You may have noticed variants like require_once or include_once. The once suffix tells PHP that if the file has already been loaded previously, it should not load it again.
This is a necessary protection layer in "vanilla" PHP. Imagine that you accidentally include the database connection file in two different places in your logic; without once, PHP would try to execute the connection twice, which would cause errors or unnecessary resource consumption.
Although it consumes a bit more memory (because PHP must check if the file already exists in the loading history), it is the recommended option to ensure that each piece of code is executed only once.
Evolution towards Frameworks: from load to use
The way of importing files has evolved drastically. In older frameworks like CodeIgniter 3, proprietary methods (such as $this->load->model()) were used to try to bring order to the chaos of imports that usually occurs in pure PHP.
However, in modern frameworks like Laravel or CodeIgniter 4, we use the use statement along with Namespaces.
Namespaces and Modern Structure
- A Namespace is like a "virtual folder". It allows two files to have the same name without clashing, as long as they are in different spaces.
- Unique Identifier: Prevents conflicts if you have, for example, a class called User for the database and another User class for administration.
- Organization: Normally, the Namespace matches the folder structure of your project (e.g., App\Http\Controllers).
By using use, you no longer need to worry about complex relative paths like ../../db/connection.php. The framework, thanks to Autoload, knows exactly where to look for the file based on its namespace.
Conclusion
Although you could configure Namespaces in pure PHP, it is a process that is already resolved and standardized in current frameworks. Therefore, understanding require_once gives you the foundation, but the professional standard today is the use of Namespaces to maintain a scalable and organized application.
I agree to receive announcements of interest about this Blog.
Learn PHP from scratch with this comprehensive guide. We cover variables, functions, conditionals (if/else, switch), and best practices to avoid spaghetti code. Prepare your foundation for mastering frameworks like Laravel!
Algunas recomendaciones:
Benjamin Huizar Barajas
Laravel Legacy - Ya había tomado este curso pero era cuando estaba la versión 7 u 8. Ahora con la ac...
Andrés Rolán Torres
Laravel Legacy - Cumple de sobras con su propósito. Se nota el grandísimo esfuerzo puesto en este cu...
Cristian Semeria Cortes
Laravel Legacy - El curso la verdad esta muy bueno, por error compre este cuando ya estaba la versi...
Bryan Montes
Laravel Legacy - Hasta el momento el profesor es muy claro en cuanto al proceso de enseñanza y se pu...
José Nephtali Frías Cortés
Fllask 3 - Hasta el momento, están muy claras las expectativas del curso