Skip to content

PHP For Beginners

https://laracasts.com/series/php-for-beginners-2023-edition

Laracasts > Learn Laravel Path > PHP For Beginners

<?php echo "Hello world"; ?>
  • 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
  • Conditions:
    if (condition) {
    /* ... */
    }
    else {
    /* ... */
    }
    Alternative syntax with : and endif:
    if (condition):
    /* ... */
    else:
    /* ... */
    endif;
  • <?= is shorthand for <?php echo and the semicolon is optional in this case
  • Arrays are declared like [ /* … */ ]
  • Loop:
    foreach ($var as $i) {
    /* ... do something with $i ... */
    }
    Alternative syntax with : and endforeach, 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"; ?>
  • 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'];
  • = 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;
  • “Lambda functions” is the technical term for “anonymous functions”, i.e. functions that are not named (function foo(a) { }, called foo(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.
  • 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 or include
  • How not to do things: duplication of code
  • Controllers are responsible for accepting and processing an incoming request and providing a response
  • 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
  • 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 key
  • http_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) { /* ... */ }

Install MySQL 8.0 on Ubuntu 22.04 running in WSL:

Terminal window
sudo apt install -y mysql-server-8.0
sudo /etc/init.d/mysql start

Create a database for this course:

Terminal window
sudo mysql -e "CREATE DATABASE myapp;"
  • 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):
    Terminal window
    sudo apt install php8.1-mysql
    sudo phpenmod pdo_mysql
  • phpenmod, phpdismod and phpquery are tools for enabling, disabling and viewing the status of PHP modules, they are included in the php-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”.
  • 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.
  • The “scope resolution operator” :: gives access to constants (“static values”) defined in a class, e.g. we used it when referencing PDO::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 the require statement
    • Good for e.g. configuration values
  • 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 the execute() method
  • 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
  • Trying to fetch a non-existing result (no rows) from the database results in the return value false
  • 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
  • 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)
  • 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 than null
  • 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
  • trim() removes whitespace from the beginning and end of a string
  • INF 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
  • __DIR__ gives the directory of the current file
  • 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) variables
  • spl_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)
  • 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 strings
  • DIRECTORY_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?”)
  • Reminder: GET requests should be idempotent
  • Browser forms only support the GET and POST (not PATCH, DELETE, etc.) HTTP request methods
  • 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']
  • 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”)
    • Laravel
      • To store something, call the controller action “store”
      • To delete something, call the controller action “destroy”
  • Place the “happy path” (execution without errors) at the bottom of the code
  • 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.
  • 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)
  • 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
  • Write comments before the actual code as a kind of to-do list right in the IDE
  • After a redirect, exit(); the current script
  • 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
  • Use password_hash to hash a password.
  • The current default used by that function is “bcrypt”.
  • The method password_verify() can be used to verify that a provided password matches a password hashed by password_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 using setcookie()).
  • When logging a user in, regenerate the session ID for security purposes using session_regenerate_id(true);.
  • 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
  • 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.
  • “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.
  • old is conventionally used as a name for the session key that stores old form data for use after a redirect.
  • In a static method, the keyword static refers to the class.
  • The keyword extends is used to inherit from a parent class. (Also, implements indicates that a class implements an interface.)
  • Exceptions can be thrown with the throw statement and caught with try/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)
  • 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 generate composer.json using a wizard (similar to how npm i generates package.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
  • 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-controlled composer.json (and composer.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 expected.