{ claus.conrad }

PHP For Beginners

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

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:
    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

06 - Arrays

  • 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}©"; ?>
    

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) { }, 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.

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 or include
  • 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 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) { /* ... */ }

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 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”.

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 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

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 the execute() 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 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

28 - Extract a Simple Validator Class

  • 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

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) 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)

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 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?”)

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”)
    • 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

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 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);.

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 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)

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 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

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-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.