Introduction

As is, AWS-CDK can not provide a proper way to work with both the proxy and certificates configuration, so in case we are behind a corporate proxy, we need to hack it.

Setup

  1. Install AWS-CDK as a global package, and check it was properly installed.

    1
    2
    npm install aws-cdk -g
    cdk --version
  2. You will need to go to the node_modules folder (example on an NVM installation: C:\NVM_1.1.7\v14.16.1\node_modules\aws-cdk\lib\api\aws-auth\sdk-provider.js):

  3. You will need to make the following changes, on switching the function parseHttpOptions on line 263:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    function parseHttpOptions(options) {
    var _a;
    const config = {};
    config.httpOptions = {};
    let userAgent = options.userAgent;
    if (userAgent == null) {
    // Find the package.json from the main toolkit
    const pkg = JSON.parse((_a = readIfPossible(path.join(
    __dirname, '..', '..', '..', 'package.json'))
    ) !== null && _a !== void 0 ? _a : '{}');
    userAgent = `${pkg.name}/${pkg.version}`;
    }
    config.customUserAgent = userAgent;
    const proxyAddress = options.proxyAddress || httpsProxyFromEnvironment();
    const caBundlePath = options.caBundlePath || caBundlePathFromEnvironment();

    if (proxyAddress && caBundlePath) {
    logging_1.debug('Using proxy server: %s', proxyAddress);
    logging_1.debug('Using CA bundle path: %s', caBundlePath);
    // eslint-disable-next-line @typescript-eslint/no-require-imports
    const ProxyAgent = require('proxy-agent');

    //some extra processing for splitting proxyAddress
    _p_address = proxyAddress.replace('//', "").split(":");
    _protocol = 'http';
    _address = 'localhost';
    _port = '8080';

    if (_p_address.legth < 0 || _p_address.length > 4){
    throw new Error('Invalid proxy address');
    }

    if (_p_address.legth === 1){
    _address = _p_address[0];
    }

    if (_p_address.legth === 2){
    if (_p_address[0].startsWith('http')){
    _protocol = _p_address[0];
    _address = _p_address[1];
    } else{
    _address = _p_address[0];
    _port = _p_address[1];
    }
    }

    if (_p_address.legth === 3){
    _protocol = _p_address[0];
    _address = _p_address[1];
    _port = _p_address[2];
    }

    // and set it
    config.httpOptions.agent = new ProxyAgent({
    protocol: _protocol + ':',
    slashes: true,
    auth: null,
    host: _address + ':' + _port,
    port: _port,
    hostname: _address_,
    hash: null,
    search: null,
    query: null,
    pathname: '/',
    path: '/',
    href: proxyAddress,
    ca: readIfPossible(caBundlePath),
    keepAlive: true,
    });
    } else {
    if (proxyAddress) { // Ignore empty string on purpose
    logging_1.debug('Using proxy server: %s', proxyAddress);
    // eslint-disable-next-line @typescript-eslint/no-require-imports
    const ProxyAgent = require('proxy-agent');
    config.httpOptions.agent = new ProxyAgent(proxyAddress);
    }
    if (caBundlePath) {
    logging_1.debug('Using CA bundle path: %s', caBundlePath);
    config.httpOptions.agent = new https.Agent({
    ca: readIfPossible(caBundlePath),
    keepAlive: true,
    });
    }
    }
    return config;
    }

Run it

Terminal configuration on Windows CMD

  1. You will need to work on CMD (stock). Add the NodeJS variable, then you can run AWS-CDK commands.

    1
    SET PATH=C:\NVM_1.1.7\v14.16.1;%PATH%
  2. Launch a CDK command.

    1
    cdk init sample-app --language=typescript

Terminal configuration via wrapper

  1. Your PATH must contain the following variables.

    1
    PATH=C:\NVM_1.1.7;C:\NVM_1.1.7\v14.16.1;C:\Program Files\Amazon\AWSCLI\bin;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\OpePATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC;.PY;.PYW
  2. Launch a CDK command.

    1
    cdk init sample-app --language=typescript

Terminal configuration on code workspaces

  1. If you are using a Visual Studio Code code-workspace, then you should specify it.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    {
    "folders": [
    {
    "path": ".."
    }
    ],
    "settings": {
    "terminal.integrated.shell.windows": "C:\\Program Files\\Git\\bin\\bash.exe",
    "terminal.integrated.env.windows": {
    "LC_ALL": "C.UTF-8",
    "PATH": "C:/NVM_1.1.7;C:/NVM_1.1.7/v14.16.1;C:/Program Files/Amazon/AWSCLI/bin;C:/WINDOWS/system32;C:/WINDOWS;C:/WINDOWS/System32/Wbem;C:/WINDOWS/System32/OpePATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC;.PY;.PYW"
    },
    "terminal.integrated.minimumContrastRatio": 7,
    }
    }
  2. Launch a CDK command.

    1
    cdk init sample-app --language=typescript

Lighthouse

Lighthouse CLI

Use Lighthouse Web Tool via CLI, you can check the documentation.

Setup

  • Install the Lighthouse CLI.
    1
    npm install -g lighthouse

Run it

Normal run

  • Use the terminal or bash script.
    1
    lighthouse https://example.com/ --output html --output-path ./lighthouse/report.html

Authenticated run

  • You need to add the extra headers.

    1
    2
    lighthouse http://www.example.com --view \
    --extra-headers="{\"Authorization\":\"...\"}"
  • How to create a basic header.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    #!/usr/bin/env python3.7
    import urllib3
    import requests
    from base64 import b64encode

    username = 'admin'
    password = 'password'

    encoded_credentials = b64encode(bytes(f'{username}:{password}',
    encoding='ascii')).decode('ascii')
    auth_header = f'Basic {encoded_credentials}'
    # the auth_header above can now be used in our API request
    # we'll look at that shortly

    # let's print the auth_header variable for testing
    print(f'Auth header: {auth_header}')

Performance budgets

Assert thresholds for performance metrics.

  • Timing budgets: time-based performance metrics like First Contentful Paint, Maximum First Input Delay, and Speed Index.

  • Resource counts: quantity of resources on a page. These thresholds can be defined per resource type or for the page overall.

  • Resource sizes: transfer size of resources on a page. These thresholds can be defined per resource type or for the page overall.

  • Define budget.json

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    [
    {
    "path": "/*",
    "options": {
    "firstPartyHostnames": ["*.my-site.com", "my-site.cdn.com"]
    },
    "timings": [
    {
    "metric": "interactive",
    "budget": 5000
    },
    {
    "metric": "first-meaningful-paint",
    "budget": 2000
    }
    ],
    "resourceSizes": [
    {
    "resourceType": "total",
    "budget": 500
    },
    {
    "resourceType": "script",
    "budget": 150
    }
    ],
    "resourceCounts": [
    {
    "resourceType": "third-party",
    "budget": 100
    }
    ]
    },
    {
    "options": {
    "firstPartyHostnames": ["*.my-site.com", "my-site.cdn.com"]
    },
    "path": "/checkout",
    "resourceSizes": [
    {
    "resourceType": "script",
    "budget": 200
    }
    ]
    }
    ]
  • Usage

    1
    lighthouse https://example.com --budget-path=budget.json

Run it on headless Chrome

  • You need a Chromium instance

    1
    2
    lighthouse --chrome-flags="--headless" https://angelesbroullon-codenotepad.statichost.eu/
    lighthouse --chrome-flags="--headless" https://angelesbroullon-codenotepad.statichost.eu/ --preset=desktop
  • In case you are on development mode on a corporate environment, you may need to disable the certificates

    1
    lighthouse --chrome-flags="--headless --ignore-certificate-errors" https://angelesbroullon-codenotepad.statichost.eu/

Lighthouse CI

Setup

  1. Install the Lighthouse CI CLI.

    1
    npm install -g @lhci/cli
  2. In the root of your repository, create a lighthouserc.js configuration file.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    module.exports = {
    ci: {
    collect: {
    /* Add configuration here */
    // If your site is static, Lighthouse can serve it itself
    staticDistDir: './public',
    // add the URL if you are running your instance
    url: ['http://localhost:8080'],
    // you may run it several times
    numberOfRuns: 5
    },
    upload: {
    /* Add configuration here */
    // if your site is not static: start your own server
    startServerCommand: 'npm run start',
    // delete it in 7 days
    target: 'filesystem',
    },
    assert: {
    assertions: {
    // off - ignore assertions
    'categories:performance': ['warn', {minScore: 1}],
    'categories:accessibility': ['error', {minScore: 1}]
    }
    },
    },
    };

Run it

  • Run Lighthouse CI from terminal.
    1
    lhci autorun

Lighthouse CI Server

Dashboard for exploring historical Lighthouse reporting.

Local version

Set up

Use it as a node project.

  1. Install the package

    1
    npm install @lhci/server sqlite3
  2. Configure the server app.js

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    const {createServer} = require('@lhci/server');

    console.log('Starting server...');
    createServer({
    port: process.env.PORT,
    storage: {
    storageMethod: 'sql',
    sqlDialect: 'sqlite',
    sqlDatabasePath: '/path/to/db.sql',
    },
    }).then(({port}) => console.log('LHCI listening on port', port));
  3. Run it locally via the CLI.

    1
    2
    3
    npm install -D @lhci/cli @lhci/server sqlite3
    npx lhci server --storage.storageMethod=sql \
    --storage.sqlDialect=sqlite --storage.sqlDatabasePath=./db.sql

Basic Authorization

  • Configure properties.
    1
    2
    3
    lhci server --basicAuth.username=myusername --basicAuth.password=mypassword
    lhci autorun --upload.basicAuth.username=myusername \
    --upload.basicAuth.password=mypassword

❗ Note
Be sure to set the same credentials in your upload step to be able to continue sending builds to your server.

Docker

  • Docker on local.
    1
    2
    3
    docker volume create lhci-data
    docker container run --publish 9001:9001 --mount='source=lhci-data,target=/data' \
    --detach patrickhulce/lhci-server

How to create a layer

Example to create a Pandas python layer

  1. Create a directory called python, and install a library locally via pip:
    1
    2
    3
    mkdir python
    cd python
    pip install -t pandas .
  2. Zip it on a parent folder.
    1
    2
    zip -r pandas_layer.zip .
    # Your zip file should have a folder named python with all content inside
  3. Upload your pandas_layer.zip to your s3 bucket.
  4. Next, deploy the AWS SAM template to create the layer:
    1
    sam deploy --guided
    For the Stack name, enter aws-sdk-layer. Enter your preferred AWS Region and accept the other defaults.
  5. After the deployment completes, the new Lambda layer is available to use. Check the available layers:
    1
    aws lambda list-layers

Example to create an AWS SDK nodeJS layer:

  1. Clone this blog post’s GitHub repo. From a terminal, execute:
    1
    2
    3
    4
    git clone https://github.com/aws-samples/aws-lambda-layers-aws-sam-examples
    # install it
    cd ./aws-sdk-layer
    npm install
  2. Create the layer directory defined in the AWS SAM template and the nodejs directory required by Lambda. Next, move the node_modules directory:
    1
    2
    mkdir -p ./layer/nodejs
    mv ./node_modules ./layer/nodejs
  3. On the AWS Console, navigate to “Lambda -> Layers” and create a layer. You may test its reference works with some dummy code like:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    import json
    import pandas as pd

    def lambda_handler(event, context):

    series = pd.Series([2, 4, 6, 8])
    return {
    'statusCode': 200,
    'body': json.dumps('Hello from Pandas, max value is '
    + str(series.max()) )
    }

How to create a lambda which uses layers

  1. Upload your lambda code on a zip to an S3 bucket.
  2. If you don’t need the layers, just remove them from the template, just like the X-Ray part. Then deploy this template on CloudFormation.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
AWSTemplateFormatVersion: '2010-09-09'
Description: "This stack creates a Lambda function that gets its code from an S3 bucket and makes use of 2 different Lambda layers"
Parameters:
LambdaBucket:
Description: S3 URI where the Lambda code zip will be located.
Type: String
Default: org-env-account-stack-templates-s3
LambdaDescription:
Description: Description of the Lambda Function.
Type: String
Default: Lambda for tests.
LambdaHandler:
Description: Handler of the Lambda Function.
Type: String
Default: lambda_function.lambda_handler
LambdaMemory:
Description: Memory available to the Lambda Function.
Type: Number
Default: 832
LambdaName:
Description: Name of the Lambda function.
Type: String
Default: TestLambda
LambdaObject:
Description: Name of the zip file that includes the Lambda code.
Type: String
Default: MyTest/Lambda_Test.zip
LambdaObjectVersion:
Description: Version of the Lambda code.
Type: String
Default: abcdeFGHij12LmN3opqRSTuV45wx67yz
LambdaRole:
Description: IAM role with permissions required to execute the Lambda function.
Type: String
Default: arn:aws:iam::123456789012:role/service-role/ChromelessTest-role-a1bcd2ef
LambdaRuntime:
Description: IAM role with permissions required to execute the Lambda function.
Type: String
Default: python3.7
LambdaTimeout:
Description: Timeout (in seconds) to execute the Lambda Function.
Type: Number
Default: 63
TracingMode:
Description: Tracing mode for integration with AWS X-Ray if needed.
Type: String
Default: Active
LambdaLayer1:
Description: ARNs of the layers that will be applied to the Lambda function, in case you need dependencies.
Type: String
Default: arn:aws:lambda:eu-west-1:123456789012:layer:LambdaInsightsExtension:10
LambdaLayer2:
Description: ARNs of the layers that will be applied to the Lambda function, in case you need dependencies.
Type: String
Default: arn:aws:lambda:eu-west-1:01234567890:layer:selenium-python-dependencies:12
Resources:
LambdaFunction:
Type: 'AWS::Lambda::Function'
Properties:
MemorySize: !Ref LambdaMemory
Description: !Ref LambdaDescription
TracingConfig:
Mode: !Ref TracingMode
Timeout: !Ref LambdaTimeout
Code:
S3ObjectVersion: !Ref LambdaObjectVersion
S3Bucket: !Ref LambdaBucket
S3Key: !Ref LambdaObject
Role: !Ref LambdaRole
Handler: !Ref LambdaHandler
FunctionName: !Ref LambdaName
Runtime: !Ref LambdaRuntime #"python3.7"
PackageType: "Zip"
Layers:
- !Ref LambdaLayer1 #LayerInsights
- !Ref LambdaLayer2 #LayerSeleniumPython

Configuration for NodeJS

Those of us who need to develop with different versions of NodeJS have been using Node Version Manager (NVM). However, due to some workstation limitations due to Corporate Security, we may not able to run all the commands successfully, so when we had to work with session variables on the terminal, we had to type extra commands every single time.

However, there is an alternative way to configure NodeJS seamlessly on Visual Studio Codium via code-workspaces.

What is a Code Workspace?

While most Integrated Development Environments (IDEs) have some kind of default “project structure”, Visual Studio Code just uses “folders” as default. However, you can go to File -> Save workspace as to create a .code-workspaces file. Its content will look like this at first:

1
2
3
4
5
6
7
8
9
{
"folders": [
{
"path": ".."
}
],
"settings": {
}
}

Most people use this feature to enable and disable extensions depending on the “project”, so the Visual Studio Codium application is lighter and there are no conflicts on extensions (e.g. different linters).

Terminal configuration on code-workspaces

With the following settings configuration we are going to:

  1. Configure Git Bash as the default terminal.
  2. Select the NodeJS version we want to use in this project.
  3. Fix the encoding issues.
  4. Fix the accessibility issues.
1
2
3
4
5
6
7
8
"settings": {
"terminal.integrated.shell.windows": "C:\\Program Files\\Git\\bin\\bash.exe",
"terminal.integrated.env.windows": {
"PATH":"C:/NVM_1.1.7/v14.9.0/",
"LC_ALL": "C.UTF-8"
},
"terminal.integrated.minimumContrastRatio": 7,
}

And we will get this final result.

Configure Git Bash as the default terminal

  • ✔️ Git bash comes with some useful tools like ssh, curl (the real curl, not the Microsoft implementation which lacks features)…

Select the NodeJS version we want to use in this project

We usually did this running this cmd commands script.

1
2
3
4
@ECHO OFF
SET PATH=%PATH%;C:\NVM_1.1.7\v14.9.0
@ECHO ON
nvm list

This classic configuration has the following problems:

  • ❌ it is a cmd solution, so we lack many commands of modern terminals.
  • ❌ it has to be run every time we use a new session.

The workspace configuration allows you to:

  • ✔️ it runs seamlessly.
  • ✔️ Git bash is a much better tool than cmd, it has more useful tools.
  • ✔️ it affects the whole workbench (linters, etc…), you only modify it when you need to upgrade NodeJs.
  • ✔️ it only affects this workspace, another workspace may have a different configuration.

Fix the encoding issues

  • ❌ Some unicode characters like greek characters and symbols can not be rendered due to not having the correct encoding configuration.
  • You can ensure this on the workspace configuration, but there is also a general fix that can be done in .minttyrc on your user folder.
    1
    2
    Locale=C
    Charset=UTF-8

Fix the accessibility issues

  • ❌ Most of the colourful terminal themes may have visibility issues according to WCAG. Maybe you, as a developer are not ffected by this, but many times we share screenshots, live coding and coloured text, so please try to prevent the exclusion of some co-workers. It will also be good for your eyes in the long term.
  • ✔️ The minimum acceptable contrast value for WCAG is 7. The highest value is 21, which is mostly black and white, but that is an extreme measure.

Extra tips

Speed dial for code-workspaces

You may use the Project dashboard extension to speed dial the different projects you are working in, as folders or code-workspaces. You just need to press Ctrl + F1 to open the dashboard, or click on its icon on the left bar.

Workspace colours

You may use the Peacock extension to change the color of your Visual Studio Codium workspace. This is great when you have multiple VS Code instances; use screen sharing tools, or use remote features, so you can quickly identify your editor. Press F1, type “peacock” and select “change to favourite colour”.

Naming convention

1
2
3
4
5
6
<?php
$first_name = 'Angeles'. // all lower case with underscore separators
function updateProduct(){} // camelCase
class ProductItem{} // StudlyCaps
const ACCESS_KEY = '123abc'; // all upper case with underscore separators
?>

Output

1
echo 'Hello World';

Variable declaration

1
2
3
4
$name = 'Angeles'; //string
$is_active = true; //boolean
$number = 7; //integer
$amount = 99.99; //float

Strings

  • Concatenate

    1
    echo 'Hello ' . $name;
  • Escape characters

    1
    2
    //string escape characters \n new line  \t tab  \\ backslash
    echo "Hello Angeles\nHello Juan";
  • Interpolation

    1
    echo "Hello $name";
  • Length

    1
    echo strlen($name);
  • Remove spaces

    1
    2
    // Remove space(s) before and after
    echo trim($text)
  • Convert cases

    1
    2
    3
    4
    echo strtolower($email);
    echo strtoupper($name);
    // Converts the first character to uppercase
    echo ucfirst($name); // 'Angeles'
  • Replace

    1
    2
    // Replace text a by text b in $text
    echo str_replace('a', 'b', $text);
  • Contains (PHP 8)

    1
    echo str_contains($name, 'ke')  # true

Numeric

  • Check

    1
    echo is_numeric('59.99'); # true
  • round number

    1
    2
    3
    // Round a number
    echo(round(0.80)); // returns 1
    echo(round(0.49)); // returns 0
  • Random

    1
    echo(rand(10, 100)); # 89

Nullable

  • Null coalesce operator

    1
    echo $name ?? 'Angeles';  //output 'Angeles' if $name is null
  • Null coalesce assignment

    1
    $name ??= 'Angeles';
  • Null safe operator (PHP 8)

    1
    2
    // return null if one ? is null
    echo $user?->profile?->activate();
  • Null safe + Null coalesce

    1
    2
    // if null, return 'Not applicable'
    echo $user?->profile?->activate() ?? 'Not applicable';

Spaceship

  • Combined comparison which will retun:
    • 0 if values on either side are equal
    • 1 if the value on the left is greater
    • -1 if the value on the right is greater
1
2
3
4
5
6
//Spaceship operator return -1 0 1
$names = ['Angeles', 'Juan', 'Luis']
usort($names, function($a, $b) {
return $a <=> $b;
}
// ['Angeles', 'Juan', 'Luis']

Debug

  • Print variables contents

    1
    2
    var_dump($names);
    print_r($names);
  • Terminate the current script

    1
    die();

Conditionals

  • Ternary operator

    1
    2
    // Ternary operator (true : false)
    echo $valid ? 'user valid' : 'user not valid';
  • If-else

    1
    2
    3
    4
    5
    6
    7
    8
    //Conditionals
    if ($condition == 10) {
    echo 'condition 10'
    } elseif ($condition == 5) {
    echo 'condition 5'
    } else {
    echo 'all other conditions'
    }
  • Compare

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    // equal no type check
    $var_1 == var_2
    // equal with type check
    $var_1 === var_2
    //not equal
    $var_1 != var_2
    //or
    $var_1 || var_2
    //and
    $var_1 && var_2
    //greater than
    $var_1 > var_2
    //less than
    $var_1 < var_2
  • Match expression (PHP 8)

    1
    2
    3
    4
    5
    6
    $type = match($color) {
    'red' => 'danger',
    'yellow', 'orange' => 'warning',
    'green' => 'success',
    default => 'Unknown'
    };

Loops

  • For

    1
    2
    3
    4
    //for loop
    for ($i = 0; $i < 20; $i++) {
    echo "i value = " . i;
    }
  • While

    1
    2
    3
    4
    5
    $number = 1;
    while ($number < 10) {
    echo 'value : ' . $number ;
    $number += 1;
    }
  • Do while

    1
    2
    3
    4
    5
    $number = 1;
    do {
    echo 'value : ' . $number ;
    $number += 1;
    } while ($number < 10);

Arrays

  • Array declaration

    1
    $names = ['Angeles', 'Juan'];
  • Add to array

    1
    2
    3
    $names = ['Angeles', 'Juan'];
    $names[] = 'Luis';
    // names: ['Angeles', 'Juan', 'Luis',
  • Spread operator

    1
    2
    3
    $names = ['Angeles', 'Juan', 'Luis'];
    $people = ['Manuel', ...$names];
    // people: ['Manuel', 'Angeles', 'Juan', 'Luis']
  • Remove array entry

    1
    2
    3
    $names = ['Angeles', 'Juan'];
    unset($names['Angeles']);
    // output: ['Angeles', 'Juan']
  • Array to string

    1
    2
    3
    $names = ['Angeles', 'Juan'];
    echo implode(', ', $names)
    //output: 'Angeles, Juan'
  • String to Array

    1
    2
    3
    $text = 'Angeles, Juan'
    echo explode(',', $text);
    // output: ['Angeles', 'Juan']
  • Direct access

    1
    2
    3
    $names = ['Angeles', 'Juan'];
    echo $names[1]
    //output: Angeles
  • Loop for each array entry

    1
    2
    3
    foreach($names as $name) { 
    echo 'Hello ' . $name;
    }
  • Loop break / continue

    1
    2
    3
    4
    5
    6
    7
    8
    $values = ['one', 'two', 'three'];
    foreach ($values as $value) {
    if ($value === 'two') {
    break; // exit loop
    } elseif ($value === 'three') {
    continue; // next loop iteration
    }
    }
  • Number of items in a Array

    1
    echo count($names);  
  • Associative array:

    1
    $person = ['age' => 30, 'hair' => 'dark'];
  • Add to associative array

    1
    $person['name'] = 'Angeles';
  • Loop associative array (key => value)

    1
    2
    3
    foreach($names as $key => $value) { 
    echo $key . ' : ' . $value
    }
  • Check if a specific key exist

    1
    echo array_key_exist('age', $person);
  • Return keys

    1
    2
    echo array_keys($person);
    // ['age', 'hair']
  • Return values

    1
    2
    echo array_values($person)
    // [30, 'dark']
  • Array filter (return a filtered array)

    1
    2
    3
    $filtered_people = array_filter($people, function ($person) {
    return $names->active;
    })
  • Array map (return transform array):

    1
    2
    3
    $only_names = array_map(function($person) {
    return [‘name’ => $person->name];
    }, $people)

Functions

  • Function declararion

    1
    2
    3
    function name($first_name, $last_name = 'default value') {
    puts $first_name . ' ' . $last_name
    }
  • Function call

    1
    name('Angeles', 'Broullon');
  • Function call with named parameters (PHP 8)

    1
    2
    name(first_name: 'Angeles', last_name: 'Broullon');
    // order can change
  • Function variables params

    1
    2
    3
    function name(...$params) {
    return $params[0] . “ “ . params[1];
    }
  • Closure function

    1
    2
    3
    Route::get('/', function () {
    return view('welcome');
    });
  • Arrow functions

    1
    Route::get('/', fn () => return view('welcome');

Files

  • File read

    1
    $file = fopen("test.txt", "r");
  • Output lines until EOF is reached

    1
    2
    3
    4
    5
    while(! feof($file)) {
    $line = fgets($file);
    echo $line. "<br>";
    }
    fclose($file);
  • File write

    1
    2
    $file = fopen('export.csv', 'a');
    $array = ['name' => 'Angeles', 'age' => 30];
  • Write key name as csv header

    1
    fputcsv($file, array_keys($array[0]));
  • Write lines (format as csv)

    1
    2
    3
    4
    foreach ($array as $row) {
    fputcsv($file, $row);
    }
    fclose($file);

Error handling

  • Throw error

    1
    2
    3
    if (someCondition) {
    throw new Exception('Data format error');
    }
  • Catch the error

    1
    2
    3
    4
    5
    try {
    $db->checkData($data)
    } catch (Exception as $e)
    echo $e->getMessage();
    }

Classes

  • Class declaration

    1
    2
    class Person {
    }
  • Object instantiation

    1
    $person = new Person
  • Class properties and constructor

    1
    2
    3
    4
    5
    6
    7
    class Person {
    protected $first_name;
    protected $last_name;
    public function __construct($first_name, $last_name) {
    $this->first_name = $first_name;
    $this->last_name = $last_name
    }
  • Constructor Property Promotion (PHP 8)

    1
    2
    3
    4
    5
    6
    7
    class Person 
    {
    public function __construct(protected $first_name, protected $last_name)
    {

    }
    }
  • Static constructor

    1
    2
    3
    4
    public static function create(...$params) {
    return new self($params)
    }
    $person = Person::create(Angeles, ‘Broullon’);
  • Class inheritance

    1
    2
    3
    4
    5
    6
    class Customer extends Person {
    public function name() {
    parent::name();
    echo 'Override method';
    }
    }
  • Static method

    1
    2
    3
    4
    5
    class Greeting {
    public static function welcome() {
    echo "Hello World!";
    }
    }
  • Call static method

    1
    greeting::welcome();
  • Static method internal call

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    class Greeting {
    public static function welcome() {
    echo "Hello World!";
    }

    public function __construct() {
    self::welcome();
    }
    }

    new Greeting();

Interfaces

1
2
3
4
5
6
7
8
9
10
11
interface Animal {
public function makeSound();
}

class Cat implements Animal {
public function makeSound() {
echo "Meow";
}
}
$animal = new Cat();
$animal->makeSound();

Trait (mix-in)

1
2
3
4
5
6
7
8
9
10
11
12
trait HelloWorld {
public function sayHello() {
echo 'Hello World!';
}
}

class Greetings {
use HelloWorld;
}

$object = new Greetings();
$object->sayHello();
0%