PHP For Beginners
Link
https://laracasts.com/series/php-for-beginners-2023-edition
Laracasts > Learn Laravel Path > PHP For Beginners
01 - How to Choose a Programming Language
02 - Tools of the Trade
- Recommended editors
- PhpStorm
- Visual Studio Code
- PHP extension
All-in-One PHP support - IntelliSense, Debug, Formatter, Code Lenses, Code Fixes, Linting, Refactoring, PHPUnit Tests, Web Server, and more.
- PHP extension
- Sublime Text
- Terminals
- macOS
- Windows
- Ways of installing PHP
- Database clients
- TablePlus
- phpMyAdmin (MySQL only)
03 - Your First PHP Tag
<?php echo "Hello world"; ?>
04 - Variables
- Statements end with a
;
- Strings are concatenated with a
.
- Variables start with a
$
sign - Strings can be single-quoted or double-quoted; variables are only evaluated in the latter
05 - Conditionals and Booleans
- Conditions:
Alternative syntax withif (condition) { /* ... */ } else { /* ... */ }
:
andendif
:if (condition): /* ... */ else: /* ... */ endif;
<?=
is shorthand for<?php echo
and the semicolon is optional in this case
06 - Arrays
- Arrays are declared like
[
/* … */]
- Loop:
Alternative syntax withforeach ($var as $i) { /* ... do something with $i ... */ }
:
andendforeach
, often used in views:foreach ($var as $i): /* ... do something with $i ... */ endforeach;
- When echo’ing a variable that should immediately be followed by some other text, we can wrap it in curly braces:
<?php echo "{$i}©"; ?>
07 - Associative Arrays
- Array indices start at zero
- Arrays can be indexed:
$books[2]
- Arrays can be nested
- Associative arrays are indexed by key instead of numbers:
$book = [ 'name' => 'Do Androids Dream of Electric Sheep', 'author' => 'Philip K. Dick' ]; echo $book['name'];
08 - Functions and Filters
=
assigns a value==
compares equality of value===
compares equality of value and type- Function definition and parameters:
function filterByAuthor($books) { // ... }
- Returning data from a function:
return 'foo';
[] =
appends a value to an array:$filteredBooks = []; $filteredBooks[] = $book;
09 - Lambda Functions
- “Lambda functions” is the technical term for “anonymous functions”, i.e. functions that are not named (
function foo(a) { }
, calledfoo(b)
), but may still be assigned to variables ($foo = function (a) { };
, called$foo(b);
). array_filter
is one of many useful functions included with PHP.
10 - Separate Logic From the Template
- The last
?>
on the page may be omitted (unless there is HTML after it) - Good idea to separate logic (e.g., accessing the database or other servers) from the HTML (also called the template or “view”)
- For reuse or separation, code files can be “imported” using
require
orinclude
12 - Page Links
- How not to do things: duplication of code
13 - PHP Partials
- Controllers are responsible for accepting and processing an incoming request and providing a response
14 - Superglobals and Current Page Styling
var_dump
converts the value of e.g. arrays and outputs them as a string- “Superglobals”, such as
$_GET
,$_POST
,$_SERVER
, are available from anywhere die()
exits processing- Ternary operator
expr ? if_truthy : else
as a shorthand for if/else
15 - Make a PHP Router
- A router maps the URI to the corresponding controller
parse_url()
splits a URI into path and query(string)array_key_exists()
checks if an array has a given keyhttp_response_code()
sets the HTTP status code- Remember: For variables to be substituted within strings, the string must be enclosed in double quotes, and the variable must be enclosed in (a single set of) curly brackets
- Set a default for a parameter to make it optional, e.g.:
function foo($var = 12345) { /* ... */ }
16 - Create a MySQL Database
Install MySQL 8.0 on Ubuntu 22.04 running in WSL:
sudo apt install -y mysql-server-8.0
sudo /etc/init.d/mysql start
Create a database for this course:
sudo mysql -e "CREATE DATABASE myapp;"
17 - PDO First Steps
- Classes 101
- Think of a class like a blueprint for anything
- Functions within a class are called “methods”
- The default visibility for a class method is “public”, but it is good coding style to declare that explicitly
- Other visibilities are e.g. “protected” and “private”
- Instances of classes are called “objects”
- Class members on objects are accessed with the
->
characters, e.g.:class Person { public $name; } $person = Person(); $person->name = 'John Doe';
- Within a method (class function), the current object can be accessed using the
$this
keyword/variable
- Remember: The string concatenation character is
.
(a dot) - Installing and enabling the PDO MySQL driver for the CLI server (assuming PHP 8.1 on Ubuntu 22.04 installed using the Ondřej Surý PPA):
sudo apt install php8.1-mysql sudo phpenmod pdo_mysql
phpenmod
,phpdismod
andphpquery
are tools for enabling, disabling and viewing the status of PHP modules, they are included in thephp-common
package (on Ubuntu 22.04)- Creating a MySQL user for the demo/course app:
CREATE USER 'myapp'@'localhost' IDENTIFIED BY 'SOME_SUPER_SECURE_PASSWORD_GOES_HERE'; GRANT ALL ON myapp.* TO 'myapp'@'localhost'; FLUSH PRIVILEGES;
- For the demo to work, I had to change the
host
in the DSN from “localhost” to “127.0.0.1”.
18 - Extract a PHP Database Class
- The constructor method is called
__construct()
in PHP. - If the PHP file only contains a class, the convention is to start the file name with a capital letter.
19 - Environments and Configuration Flexibility
- The “scope resolution operator”
::
gives access to constants (“static values”) defined in a class, e.g. we used it when referencingPDO::FETCH_ASSOC
- http_build_query()
converts an associative array to a querystring- A PHP file can
return
something - and that return value can be assigned to a variable in another file using therequire
statement- Good for e.g. configuration values
20 - SQL Injection Vulnerabilities Explained
- To avoid SQL injection, substitute any dynamic (user-provided) values in SQL statements with
?
or:name
placeholders, and bind the actual values by providing them as an array to theexecute()
method
21 - Database Tables and Indexes
- Unique indices prevent multiple rows from having the same value in the same column (e.g. multiple users having the same email address)
- Foreign keys reference other tables
ON UPDATE
/ON DELETE
configure rules to keep the database integrity intact, e.g. here to automatically delete all of a user’s notes when the user gets deleted
22 - Render the Notes and Note Page
23 - Introduction to Authorization
- Trying to fetch a non-existing result (no rows) from the database results in the return value
false
24 - Programming is Rewriting
25 - Intro to Forms and Request Methods
- Good coding style / conventions:
- Start all controllers/views/etc. related to the same “class”/topic with the same expression, e.g.:
- If one controller relates to one view - call the files the same
- A plural route (“/notes”) should show a list of items of that type
- A singular route (“/note/ID-SLUG”) should show a single note with that ID/slug
- All form input fields should have a corresponding name, which will often be the same as the property/database column
- GET requests should be idempotent (not changing data on the server/database, except request logging obviously)
- POST request data can be accessed using the superglobal
$_POST
26 - Always Escape Untrusted Input
- Always assume that the user is guilty (i.e. malicious) until proven otherwise
htmlspecialchars()
converts HTML code to plain text (no risk of XSS when displaying it)
27 - Intro to Form Validation
- Use client-side validation to provide faster feedback to the regular user, but server-side validation to avoid abuse by malicious actors (or users with Javascript disabled for some reason)
isset()
can be used to determine if a variable exists (including whether a key exists in an associate array) and is set to something else thannull
- The “null coalescing operator”
??
, introduced in PHP 7, uses the following value if the preceding one does not exist, e.g. the following snippets are equivalent:<?= isset($_POST['body']) ? $_POST['body'] : '' ?>
<?= $_POST['body'] ?? '' ?>
strlen()
returns the length of a string
28 - Extract a Simple Validator Class
trim()
removes whitespace from the beginning and end of a stringINF
is a global constant for “infinity”, i.e. the largest number- A “pure function” does not require any state from the outside (“self-contained”; only relying on its input to produce its output)
- Methods which are pure functions can be made “static”, which means they can be called directly using the class and the
::
operator, without having to instantiate an object of the class first filter_var()
can e.g. be used for validating that something looks like a valid email address
29 - Resourceful Naming Conventions
__DIR__
gives the directory of the current file
30 - PHP Autoloading and Extraction
- The path to the project root is often called
BASE_PATH
. - Constants are declared using the
const
keyword and do not start with a$
sign. extract()
turns an array into a set of (declared) variablesspl_autoload_register()
can be used to autoload classes and avoid the issue of having to require them (and the risk of requiring them twice, resulting in an error about duplicate declaration)
31 - Namespacing: What, Why, How?
- The
namespace
keyword is used to declare a namespace in PHP - Namespaces are used to prevent conflicts between classes that have the same name and can be used to organize code by grouping related classes together
- When using a namespaced file, use the
use
keyword to “import” it str_replace()
replaces occurances of strings in strings with other stringsDIRECTORY_SEPARATOR
is a global constant that contains the current operating system’s directory separator (e.g.,/
or\
)- By now it should be obvious that the convention is to name constants with all capital letters 😀
- Every class mentioned in a “namespaced” class is assumed to be in the same namespace
- To reference a class in the “global” namespace (i.e. without a namespace), prefix it with the
\
(backslash) character - Instead, one can also
use
a class from the global namespace, which also serves as a sort of documentation (answering the question “which other classes are used within this class?”)
32 - Handle Multiple Request Methods From a Controller Action?
- Reminder: GET requests should be idempotent
- Browser forms only support the GET and POST (not PATCH, DELETE, etc.) HTTP request methods
33 - Build a Better Router
- For now, consider PATCH and PUT synonyms
- A
protected
property is not available outside the class - To simulate DELETE requests using browser forms, it is common to override the intended method using a hidden field
_method
- The
compact
method takes one or multiple strings and creates an associative array, where the strings are the keys and the values are$
+string, e.g.$a = "b"; $b = "c"; compact('a', 'b'); // ['a' => 'b', 'b' => 'c']
34 - One Request, One Controller
- Conventions
- REST
- To store something, make a POST request to the plural, e.g.
POST /notes
- To delete something, use the HTTP DELETE method, or if that is not feasible (e.g. because of not wanting to depend on JavaScript), use the HTTP POST method and a hidden form field called e.g. “_method” that provides the intended HTTP method (e.g. “DELETE”)
- To store something, make a POST request to the plural, e.g.
- Laravel
- To store something, call the controller action “store”
- To delete something, call the controller action “destroy”
- REST
- Place the “happy path” (execution without errors) at the bottom of the code
35 - # Make Your First Service Container
- The purpose of this lesson is to understand the concepts behind service containers. In the real world, a framework like Symphony or Laravel would provide this functionality.
- “bind” => “add something to the container”
- Binds a key (string) to a factory function (builder, resolver)
- “resolve” => “get something from the container”
call_user_func
is a method that calls a function- To throw an exception, use the
throw
keyword, e.g.throw new \Exception();
- Static functions can be called without instantiating an object of a class
- A class has a static property
::class
that returns its fully namespaced name - In addition to the naive container built in this lesson, Laravel service containers support singletons (get the same instance no matter how many times you resolve it) and automatic dependency resolution.
36 - Updating With PATCH Requests
- Always think about “where could things get out of sync, what could I possibly consolidate (refactor)”
- Laravel conventions for CRUD controller names (with purpose; corresponding HTTP method; and SQL verb)
create
(view create form; GET; N/A)destroy
(delete; DELETE; DELETE)edit
(show one, editable; GET; SELECT)index
(show all; GET; SELECT)show
(show one, read-only; GET; SELECT)store
(persist; POST; INSERT)update
(update existing; PATCH; UPDATE)
37 - PHP Sessions 101
- Session variables are in
$_SESSION
superglobal - Sessions are started using
session_start();
- The default for storing sessions on the server is as files in the temporary directory
38 - Register a New User
- Write comments before the actual code as a kind of to-do list right in the IDE
- After a redirect,
exit();
the current script
39 - Introduction to Middleware
- Usually some pages should only be available to authenticated users - and some others only to anonymous users (such as the sign-up page)
- Middleware:
- Think of middleware as a bridge between the request and the core of the application
- Used for e.g. authentication
array_key_last()
can return the last key in an array- The syntax
static::member
can be used to refer to static members of the current class
40 - Manage Passwords Like This For The Remainder of Your Career
- Use
password_hash
to hash a password. - The current default used by that function is “bcrypt”.
41 - Log In and Log Out
- The method
password_verify()
can be used to verify that a provided password matches a password hashed bypassword_hash()
. - A request to logout destroys (session) data on the server and should therefore use the DELETE HTTP method.
session_destroy()
destroys the session data on the server.setcookie()
can be used to set a cookie, which includes deleting an existing cookie (by using the same name and setting an expiry time in the past).session_get_cookie_params()
returns the values (path, domain, etc.) used for the session cookie (necessary when deleting it usingsetcookie()
).- When logging a user in, regenerate the session ID for security purposes using
session_regenerate_id(true);
.
42 - Extract a Form Validation Object
- Separate code specific to the application from “core infrastructure” code (different folders and namespaces)
empty()
returns a boolean about whether the argument (array, etc.) is empty
43 - Extract an Authenticator Class
- It is the controller’s responsibility to return a view (don’t put such code in utility classes).
75% of programming is reading. - Jeffrey Way
- When instantiating an object without passing constructor arguments, the parentheses after the class name are optional.
44 - The PRG Pattern (and Session Flashing)
- “POST -> redirect -> GET” avoids the issue where the user navigates backwards and the browser asks whether they want to resubmit the form.
unset()
destroys a variable.- “Flashing” means keeping data in the session for a short time, usually destroying it after the following request.
45 - Flash Old Form Data to the Session
old
is conventionally used as a name for the session key that stores old form data for use after a redirect.
46 - Automatically Redirect Back Upon Failed Validation
- In a static method, the keyword
static
refers to the class. - The keyword
extends
is used to inherit from a parentclass
. (Also,implements
indicates that a class implements aninterface
.) - Exceptions can be thrown with the
throw
statement and caught withtry
/catch
. - In PHP 8, by prefixing the constructor’s arguments with a visibility (e.g.
public
/protected
), they no longer need to be assigned to instance attributes manually (see Constructor Property Promotion):public function __construct(public array $attributes) { // ... }
- The
readonly
keyword means that a variable can only be assigned to once. - Delegate instead of micromanaging (move functionality out of the controller)
47 - Composer and Free Autoloading
- Composer is a dependency manager and autoloader, so we can forget about
spl_autoload_register
🤗 - “PSR” => “PHP Standard Recommendation”
- “PSR-4” => a spec for autoloading
composer init
to generatecomposer.json
using a wizard (similar to hownpm i
generatespackage.json
)composer dump-autoload
to generate autoload files- In
composer.json
->autoload
->psr-4
:- The key (namespace) needs to end with a namespace separator (backslash) (escaped in JSON using another backslash)
- The value (folder path) needs to end with a folder separator (forward slash)
- Only the top-level namespaces need to be mapped
48 - Install Two Composer Packages: Collections and PestPHP
- Ways to search for packages
- Packagist.org - ordered by popularity (number of downloads)
composer search KEYWORD
- Collections = like arrays, but with extra functions
composer require
to install packages and persist them in the source-controlledcomposer.json
(andcomposer.lock
)composer require --dev
for packages that are not used in production (but only during development/testing)- Recommended unit test runner: Pest
- Test files should end with the suffix “Test”(.php)
Arrow functions were introduced in PHP 7.4 as a more concise syntax for anonymous functions.
- Unit tests allow us to refactor with more confidence that things will still work as
expect
ed.