FCM Integration with Spring Boot To Send Push Notification From Server Side.


Hey Guys, recently i have integrated FCM( Firebase Cloud Messaging) with one of my spring boot application. So I would like to share my experience with you.

Some Basics Steps You Need To Follow:
1) Please make sure client application registered under Firebase.

2) Now we need to generate Firebase SDK admin key. This is basically JSON file and the purpose of this file is for server side authorization.You can get more details under https://firebase.google.com/docs/cloud-messaging/auth-server .

3) To get Admin SDK go to Project Setting -> Service Accounts -> Check Java radio button -> Finally click on Generate new private key and save it.


4) Now we need to use generated private JSON file in our spring boot application.So for this I am assuming you have already Spring Boot application , if you don't have then you can create from here https://start.spring.io/

5) Create one folder under src/main/resources in your spring boot application. In my case I have created fcm folder. Now put you private key under this folder.

6) In your application.properties file create key/value like app.firebase-configuration-file=fcm/dummy-d7bd4-firebase-adminsdk-l3psc-8c2aa79daa.json
Note : value key contains location of your private JSON file.

7) Add Firebase dependency in pom.xml file.

<dependency>
    <groupId>com.google.firebase</groupId>
    <artifactId>firebase-admin</artifactId>
    <version>6.8.1</version>
</dependency>

8) Now we need to initialize Firebase application , for this we need private key location so to access the location we can use @Value annotation with key name. Create class FCMInitializer with file name FCMInitializer.java

package com.pushnotification.fcm.service;

import java.io.IOException;

import javax.annotation.PostConstruct;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;

import com.google.auth.oauth2.GoogleCredentials;
import com.google.firebase.FirebaseApp;
import com.google.firebase.FirebaseOptions;

@Service
public class FCMInitializer {

    @Value("${app.firebase-configuration-file}")
    private String firebaseConfigPath;

    Logger logger = LoggerFactory.getLogger(FCMInitializer.class);

    @PostConstruct
    public void initialize() {
        try {
            FirebaseOptions options = new FirebaseOptions.Builder()
                    .setCredentials(GoogleCredentials.fromStream(new ClassPathResource(firebaseConfigPath).getInputStream())).build();
            if (FirebaseApp.getApps().isEmpty()) {
                FirebaseApp.initializeApp(options);
                logger.info("Firebase application has been initialized");
            }
        } catch (IOException e) {
            logger.error(e.getMessage());
        }
    }

}

In the above code snippets , initialize() method is being called on application start up due to @PostConstruct annotaction.

9) Create Class FCMService with @Service annotation which contains some different types of methods. Create class with file name FCMService.java

package com.pushnotification.fcm.service;

import java.time.Duration;
import java.util.Map;
import java.util.concurrent.ExecutionException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import com.google.firebase.messaging.AndroidConfig;
import com.google.firebase.messaging.AndroidNotification;
import com.google.firebase.messaging.ApnsConfig;
import com.google.firebase.messaging.Aps;
import com.google.firebase.messaging.FirebaseMessaging;
import com.google.firebase.messaging.Message;
import com.google.firebase.messaging.Notification;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.pushnotification.fcm.model.PushNotificationRequest;

@Service
public class FCMService {

    private Logger logger = LoggerFactory.getLogger(FCMService.class);

    public void sendMessage(Map<String, String> data, PushNotificationRequest request)
            throws InterruptedException, ExecutionException {
        Message message = getPreconfiguredMessageWithData(data, request);
        Gson gson = new GsonBuilder().setPrettyPrinting().create();
        String jsonOutput = gson.toJson(message);
        String response = sendAndGetResponse(message);
        logger.info("Sent message with data. Topic: " + request.getTopic() + ", " + response+ " msg "+jsonOutput);
    }

    public void sendMessageWithoutData(PushNotificationRequest request)
            throws InterruptedException, ExecutionException {
        Message message = getPreconfiguredMessageWithoutData(request);
        String response = sendAndGetResponse(message);
        logger.info("Sent message without data. Topic: " + request.getTopic() + ", " + response);
    }

    public void sendMessageToToken(PushNotificationRequest request)
            throws InterruptedException, ExecutionException {
        Message message = getPreconfiguredMessageToToken(request);
        Gson gson = new GsonBuilder().setPrettyPrinting().create();
        String jsonOutput = gson.toJson(message);
        String response = sendAndGetResponse(message);
        logger.info("Sent message to token. Device token: " + request.getToken() + ", " + response+ " msg "+jsonOutput);
    }

    private String sendAndGetResponse(Message message) throws InterruptedException, ExecutionException {
        return FirebaseMessaging.getInstance().sendAsync(message).get();
    }

    private AndroidConfig getAndroidConfig(String topic) {
        return AndroidConfig.builder()
                .setTtl(Duration.ofMinutes(2).toMillis()).setCollapseKey(topic)
                .setPriority(AndroidConfig.Priority.HIGH)
                .setNotification(AndroidNotification.builder().setSound(NotificationParameter.SOUND.getValue())
                        .setColor(NotificationParameter.COLOR.getValue()).setTag(topic).build()).build();
    }

    private ApnsConfig getApnsConfig(String topic) {
        return ApnsConfig.builder()
                .setAps(Aps.builder().setCategory(topic).setThreadId(topic).build()).build();
    }

    private Message getPreconfiguredMessageToToken(PushNotificationRequest request) {
        return getPreconfiguredMessageBuilder(request).setToken(request.getToken())
                .build();
    }

    private Message getPreconfiguredMessageWithoutData(PushNotificationRequest request) {
        return getPreconfiguredMessageBuilder(request).setTopic(request.getTopic())
                .build();
    }

    private Message getPreconfiguredMessageWithData(Map<String, String> data, PushNotificationRequest request) {
        return getPreconfiguredMessageBuilder(request).putAllData(data).setToken(request.getToken())
                .build();
    }

    private Message.Builder getPreconfiguredMessageBuilder(PushNotificationRequest request) {
        AndroidConfig androidConfig = getAndroidConfig(request.getTopic());
        ApnsConfig apnsConfig = getApnsConfig(request.getTopic());
        return Message.builder()
                .setApnsConfig(apnsConfig).setAndroidConfig(androidConfig).setNotification(
                        new Notification(request.getTitle(), request.getMessage()));
    }
}

10) Now I am going to add one more service layer. Create class PushNotificationService with file name PushNotificationService.java

package com.pushnotification.fcm.service;

import java.util.HashMap;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.pushnotification.fcm.model.PushNotificationRequest;

@Service
public class PushNotificationService {

    private Logger logger = LoggerFactory.getLogger(PushNotificationService.class);
    private FCMService fcmService;

    public PushNotificationService(FCMService fcmService) {
        this.fcmService = fcmService;
    }

    public void sendPushNotification(PushNotificationRequest request) {
        try {
            fcmService.sendMessage(getSamplePayloadData(), request);
        } catch (Exception e) {
            logger.error(e.getMessage());
        }
    }

    public void sendPushNotificationWithoutData(PushNotificationRequest request) {
        try {
            fcmService.sendMessageWithoutData(request);
        } catch (Exception e) {
            logger.error(e.getMessage());
        }
    }

    public void sendPushNotificationToToken(PushNotificationRequest request) {
        try {
            fcmService.sendMessageToToken(request);
        } catch (Exception e) {
            logger.error(e.getMessage());
        }
    }

    private Map<String, String> getSamplePayloadData() {
        Map<String, String> pushData = new HashMap<>();
        pushData.put("messageId", "msgid");
        pushData.put("text", "txt");
        pushData.put("user", "pankaj singh");
        return pushData;
    }
}

Note : Create these all three above files under the service layer.

11) Now create two files under model layer PushNotificationRequest.java , PushNotificationResponse.java

package com.pushnotification.fcm.model;

import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Setter
@Getter
@NoArgsConstructor
public class PushNotificationRequest {

    private String title;
    private String message;
    private String topic;
    private String token;  
}
package com.pushnotification.fcm.model;
public class PushNotificationResponse {

    private int status;
    private String message;

    public PushNotificationResponse() {
    }

    public PushNotificationResponse(int status, String message) {
        this.status = status;
        this.message = message;
    }

    public int getStatus() {
        return status;
    }

    public void setStatus(int status) {
        this.status = status;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}

12) Create controller class to test push notification.Create file PushNotificationController.java

package com.pushnotification.fcm.controller;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import com.pushnotification.fcm.model.PushNotificationRequest;
import com.pushnotification.fcm.model.PushNotificationResponse;
import com.pushnotification.fcm.service.PushNotificationService;

@RestController
public class PushNotificationController {

    private PushNotificationService pushNotificationService;

    public PushNotificationController(PushNotificationService pushNotificationService) {
        this.pushNotificationService = pushNotificationService;
    }

    @PostMapping("/notification/topic")
    public ResponseEntity sendNotification(@RequestBody PushNotificationRequest request) {
        pushNotificationService.sendPushNotificationWithoutData(request);
        return new ResponseEntity<>(new PushNotificationResponse(HttpStatus.OK.value(), "Notification has been sent."), HttpStatus.OK);
    }

    @PostMapping("/notification/token")
    public ResponseEntity sendTokenNotification(@RequestBody PushNotificationRequest request) {
        pushNotificationService.sendPushNotificationToToken(request);
        return new ResponseEntity<>(new PushNotificationResponse(HttpStatus.OK.value(), "Notification has been sent."), HttpStatus.OK);
    }

    @PostMapping("/notification/data")
    public ResponseEntity sendDataNotification(@RequestBody PushNotificationRequest request) {
        pushNotificationService.sendPushNotification(request);
        return new ResponseEntity<>(new PushNotificationResponse(HttpStatus.OK.value(), "Notification has been sent."), HttpStatus.OK);
    }   
}

Finally we have configured everything for push notification.So our code is ready to send the push notification.


We have mainly three use cases:
a) Push notification based on topics. In this kind of notification we don't required any device token. So based on topic configuration push notification will work.

For this you can use end point : /notification/topic

b) Push notification with token.With this end point we can send only title and body part.

For this you can use end point : /notification/token

c) Push notification with additional payload data. With this end point we can send title,body and some additional key/pair data.

For this you can use end point : /notification/data

If you want to test please use postman and pass JSON body like :

{
	"title":"Put the push notification title here",
	"message":"Put here push notification body here",
	"token":"f65ewWeHOUs:APA91bH2mVv-cVpjVv4mJZxkugeNoJJ_AL-Bl_Kfosz26rk1nTJREp-_b9eEzojh3GgvGxtu1VXlyXTxc5j_jQNMl0oBEEw2oe_knHVIpvdAKMG6qya6"
}

Note : You can download full working source code from my repository link https://github.com/firststepitsolution/push-notification-with-fcm-and-spring-boot I have tested on both platform (IOS and Android) and its working as expected.

Data Type In Java

There are two data types in JAVA. Lets take a graphical representation to understand it.
Data Type In Java

Lets take graphical representation to understand the primitive data type memory required , value holding capacity range and their default value.

Primitive data type memory, range and their default value

Lets take a example to understand the primitive data type:

1) boolean primitive data type example:

package primitiveDataType;

/**
 * 
 * boolean is a primitive data type and it takes 1 bits of memory
 * Its default value is false
 */
public class BooleanPrimitiveDataType {

	public static void main(String[] args) {
	boolean booleanVariable=true;
	System.out.println("Boolean value is : "+booleanVariable);
	}
}

2) byte primitive data type example:

package primitiveDataType;

/**
 * 
 * byte is a primitive data type and takes 8 bits(1 byte) of memory
 * Its value-range lies between -128 to 127 (inclusive)
 * Its minimum value is -128 and maximum value is 127
 * Its default value is 0 
 *
 */
public class BytePrimitiveDataType {

 public static void main(String[] args) {
	byte byteVariable=127;
	System.out.println(byteVariable);
	byteVariable='p';
	System.out.println((char)byteVariable);
 }
}

3) char primitive data type example:
package primitiveDataType;

/**
 * 
 * short is a primitive data type and takes 16 bits(2 byte) of memory
 * Its value range lies between 
 * '\u0000' (or 0) to '\uffff' (or 65,535 inclusive)
 * Its default value is '\u0000' 
 *
 */
public class CharPrimitiveDataType {

 public static void main(String[] args) {
	char name='p';
	System.out.println(name);
 }
}

4) short primitive data type example:

package primitiveDataType;

/**
 * 
 * short is a primitive data type and takes 16 bits(2 byte) of memory
 * Its value-range lies between -32,768 to 32,767 (inclusive).
 * Its minimum value is -32,768 and maximum value is 32,767. Its default value is 0. 
 *
 */
public class ShortPrimitiveDataType {

 public static void main(String[] args) {
	//It will accept only max value 32767
	short shortVariable=32767;
	System.out.println(shortVariable);
	shortVariable=-32768;
	System.out.println(shortVariable);
		
 }
}

5) int primitive data type example:

package primitiveDataType;

/**
 * 
 * short is a primitive data type and takes 32 bits(4 byte) of memory
 * Its value range lies between - 2,147,483,648  
 * to 2,147,483,647  (inclusive)
 * Its minimum value is -32,768 and maximum value is 32,767
 * Its default value is 0
 *
 */
public class IntPrimitiveDataType {

 public static void main(String[] args) {
 /**
  * It will accept only max value 2,147,483,647, 
  * if you will try to put above the mentioned range
  * it will throw error
  */
 int intVariable=2147483647;
 System.out.println("Max acceptable value is "+intVariable);
 intVariable=-2147483648;
 System.out.println("Min acceptable value is :"+intVariable);
		
 }
}

6) long  primitive data type example:

package primitiveDataType;

/**
 * 
 * short is a primitive data type and takes 64 bits(8 byte) of memory
 * Its value range lies between
 * -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807(inclusive)
 * Its minimum value is -9,223,372,036,854,
 * 775,808 and maximum value is 9,223,372,036,854,775,807
 * Its default value is 0L 
 *
 */
public class LongPrimitiveDataType {

 public static void main(String[] args) {
/**
 * It will accept only max value 9,223,372,036,854,775,807, 
 * if you will try to put above the mentioned 
 * range it will throw error
 * All literal  numbers in java are by default ints,
 * which has range -2147483648 to 2147483647 inclusive.
 * Your literals are outside this range, 
 * so to  make this compile you need to indicate they're
 * long literals (ie suffix with L):
 * You must use L to say to the compiler that it is a long literal.
 */
 long longVariable=9223372036854775807L;
 System.out.println("Max acceptable value is "+longVariable);
 longVariable=-9223372036854775808L;
 System.out.println("Min acceptable value is :"+longVariable);
		
 }
}

7) float  primitive data type example:

package primitiveDataType;

/**
 * 
 * float is a primitive data type and takes 32 bits(4 byte) of memory
 * The smallest decimal is 1.40239846 x 10^-45, 
 * and the largest value is 3.40282347 x 10^38.
 * Float range is much difference than the other primitive data type.
 * Its default value is 0.0f
 */
public class FloatPrimitiveDataType {

 public static void main(String[] args) {
	float floatVariable=9223.5f;
	System.out.println("Float value is : "+floatVariable);
		
 }
}

8) double primitive data type example:

package primitiveDataType;

/**
 * 
 * double is a primitive data type and takes 64 bits(8 byte) of memory
 * The range is 4.9406564584124654 x 10^-324 
 * to 1.7976931348623157 x 10^308. That range can
 * also be positive or negative.
 * Its default value is 0.0d
 */
public class DoublePrimitiveDataType {

 public static void main(String[] args) {
  double doubleVariable=9223.50006d;
  System.out.println("Double value is : "+doubleVariable);
 }
}

Note : You can download full source code from git repository https://github.com/firststepitsolution/java-core

Java Variable Naming Conventions.

Some basic convention rules for java variable:
1. Variable name always start with letter rather than number,$(dollar) and _(underscore).
Valid Variables Name Based On Convention:
int marks, int sumOfTwoNumbers, int listOfStudents etc
Variables Name Without Naming Convention:
int $marks, int _marks, int sum_Of_Two_Numbers, int list_of_students etc ( these all variables will work but i will suggest to not use these kind of variables and you must follow the proper naming convention for proper understanding of code and their meaning.
Invalid Variable:
int 1marks, int sum&Of, int list%Of etc
2. Name should be meaningful full word. If your variable name contains combination of two or more words then first word should be start with lower letter and then remaining words first letter should be start with capital.
3. If variables stores constant value then variable name should be in capital and if more then two words then separate words with underscore(_).
Example:
static final int RECORDS_PER_PAGE = 10;
static final int MAX_RECORDS_PER_PAGE=100;
4. Special characters are not allowed like #$%^&*@ etc
5. Variable are case-sensitive.

New Operators under PHP7 version

  1. Null coalescing operator ( ?? ) : This operator is a replacement of ternary operator  in conjunction with isset(). It returns its first operand if it exists and is not NULL; otherwise it returns its second operand

If you are aware about ternary operator then well an good if not then I am giving you one example throw which you can understand and then I will try to explain how does Null coalescing operator work.

Example Of Ternary Operator:

Syntax: statement1 ? statement2 : statement3;
If statement1 is true then statement2 will be executed otherwise statement3 will be executed.

<?php
$a = 100;
echo $a ? $a : 'statement2';

Output : 100

<?php
$a = '';
echo $a ? 'statement1' : 'statement2';

Output : statement2
<?php
$a = '';
echo isset($a) ? 'statement1' : 'statement2'; Output : statement1

<?php
echo $a ? 'statement1' : 'statement2';

Output : Notice undefined variable a;
<?php
$a=null;
echo $a ? 'statement1' : 'statement2';
Output : statement2;



Example Of Null coalescing operator: Take the above example to understand the null coalescing operator.
Syntax: statement1 ?? statement2;
So in this case if statement1 exist and not null then return statement1 otherwise return statement2.

<?php
$a = 100;
echo $a ?? 'statement1';
Output :  100

<?php
$a = '';
echo $a ?? 'statement1';
Output :   in this case blank space will print  because of  " ??"  operator will check isset and not null

<?php
echo $a ?? 'statement1';
Output :  statement1
Note:  In case of ternary operator it will throw Notice error in the above example  but in case of  Null coalescing operator , it will not throw error because  of this operator will check isset as well as null at time.

<?php
$a = null;
echo $a ?? 'statement1';

Output :  statement1    ( Second operand executed because of $a is NULL)

So I have tried to explain purpose and use of Null coalescing operator  with the help of practical example .

2. Spaceship operator ( <=> ) : This operator works on two operands, if first operand is greater than second operand then this operator return 1, if first operand less than second operand then it return -1 and both operand equal then it return 0.

I have tried to explain the use of spaceship operator with the help of below example.

<?php
// Comparison with integer values
$a = 10;
$b = 5;

if (($a <=> $b)==1) // this comparison return 1 because of a is greater than b
echo "Variable a is greater than variable b";

// Output is : Variable a is greater than variable b

if (($b <=> $a)==-1) // this comparison return -1
echo "<br>Variable b is less than variable a";
// Output is : Variable b is less than variable a

$a = 5;
$b = 5;

if (($a <=> $b) == 0) // this comparison return 0
echo "<br>Variable a and variable b are equal";
// Output is : Variable a and variable b are equal

// comparison with float values
$a = 10.01;
$b = 10.001;

if (($a <=> $b)==1) // this comparison return 1
echo "<br><br>Variable a is greater than variable b";

// Output is : Variable a is greater than variable b

if (($b <=> $a)==-1) // this comparison return -1
echo "<br>Variable b is less than variable a";
// Output is : Variable b is less than variable a

$a = 10.00;
$b = 10.00;

if (($a <=> $b) == 0) // this comparison return 0
echo "<br>Variable a and variable b are equal";
// Output is : Variable a and variable b are equal

// String comparison

$a = "applered";
$b = "apple";

if (($a <=> $b)==1) // this comparison return 1
echo "<br><br>Variable a is greater than variable b";

// Output is : Variable a is greater than variable b

if (($b <=> $a)==-1) // this comparison return -1
echo "<br>Variable b is less than variable a";
// Output is : Variable b is less than variable a

$a = "apple";
$b = "apple";

if (($a <=> $b) == 0) // this comparison return 0
echo "<br>Variable a and variable b are equal";
// Output is : Variable a and variable b are equal

// Array comparison with integer values

$a = array(1,2,4,4); // Number of elements are 4 and the sum of elements is 11
$b = array(1,2,3,4); // Number of elements are 4 and the sum of elements is 10

if (($a <=> $b)==1) // this comparison return 1
echo "<br><br>Variable a is greater than variable b";

// Output is : Variable a is greater than variable b

if (($b <=> $a)==-1) // this comparison return -1
echo "<br>Variable b is less than variable a";
// Output is : Variable b is less than variable a

$a = array(1,2,3,4);
$b = array(1,2,3,4);

if (($a <=> $b) == 0) // this comparison return 0
echo "<br>Variable a and variable b are equal";
// Output is : Variable a and variable b are equal

// Array comparison with string values

$a = array("a","b","d"); // Number of elements are 3
$b = array("a","b","c"); // Number of elements are 3

if (($a <=> $b)==1) // this comparison return 1 because of both array have a and b which are same but the thirst element in $a has d which have the higher value than c of array $b
echo "<br><br>Variable a is greater than variable b";

// Output is : Variable a is greater than variable b

if (($b <=> $a)==-1) // this comparison return -1
echo "<br>Variable b is less than variable a";
// Output is : Variable b is less than variable a

$a = array("a","b","c");
$b = array("a","b","c");

if (($a <=> $b) == 0) // this comparison return 0
echo "<br>Variable a and variable b are equal";
// Output is : Variable a and variable b are equal

// Object comparison

$a = (object) ["a" => "b"];
$b = (object) ["a" => "a"];

if (($a <=> $b)==1) // this comparison return 1
echo "<br><br>Variable a is greater than variable b";

// Output is : Variable a is greater than variable b

if (($b <=> $a)==-1) // this comparison return -1
echo "<br>Variable b is less than variable a";
// Output is : Variable b is less than variable a

$a = (object) ["a" => "a"];
$b = (object) ["a" => "a"];

if (($a <=> $b) == 0) // this comparison return 0
echo "<br>Variable a and variable b are equal";
//Output is : Variable a and variable b are equal

If you want to check the above example then please copy and past to your PHP IDE.

Major changes in php7

  1.  Improvement In Exception Handling.
  2.  Few New Operators Added.
  3. Type Declaration is possible.
  4. Constant Arrays using define().
  5. Anonymous classes.
  6. Unicode codepoint escape syntax.
  7. Closure::call().
  8. Filtered unserialize().
  9. IntlChar.
  10. Group use declarations.
  11. Generator Return Expressions.
  12. Generator delegation.
  13. Integer division with intdiv().
  14. Session options.
  15. preg_replace_callback_array().
  16. CSPRNG Functions.
  17. Improvement In Speed.

Zend Framework 2 and 3 Installation Using Composer On Linux Machine

Step 1 -> Make sure composer is installed on your system. If not then     you can use this command to install composer (curl -sS https://getcomposer.org/installer | sudo php -- --install-dir=/usr/local/bin --filename=composer )

If you want to install curl then you can use this command( sudo apt-get install curl) 

Step 2 -> Use below command to install Zf2 skeleton application on your local machine.You can put your desire version like  ^2.4. If you will not use version number then it will download latest version of zend framework.

Command :  composer create-project zendframework/skeleton-application path to install ^2.4

Example : If you want to install skeleton application under the htdocs directory then you can use like

composer create-project zendframework/skeleton-application opt/lampp/htdocs/zf2 ^2.4 

Stpe 3 -> After successfully installation you will get directory structure  like 

application_root/
    config/
        application.config.php
        autoload/
            global.php
            local.php
            // etc.
    data/
    module/
    vendor/
    public/
        .htaccess
        index.php
    init_autoloader.php

PHP 7 new exception hierarchy

interface Throwable
    |- Exception implements Throwable
        |- ...
    |- Error implements Throwable
        |- TypeError extends Error
        |- ParseError extends Error
        |- ArithmeticError extends Error
            |- DivisionByZeroError extends ArithmeticError
        |- AssertionError extends Error

In the older versions PHP can not handle fatal error but using PHP7 we can handle fatal error rather than halting the execution.

Throwable interface has the following declared methods :

interface Throwable
{
    public function getMessage(): string;
    public function getCode(): int;
    public function getFile(): string;
    public function getLine(): int;
    public function getTrace(): array;
    public function getTraceAsString(): string;
    public function getPrevious(): Throwable;
    public function __toString(): string;
}

To catch Exception and Error object we can use throwable in try/catch block. That means  Throwable may be used in try/catch blocks to catch both Exception and Error objects but it would be good if you will use specific exception class according to the situation.

-> Explanation and use of  Error class.

Virtually all errors in PHP 5.x that were fatal errors or recoverable fatal errors now throw instances of Error in PHP 7.

Example: How to catch fatal error.

<?php
try{
    add();
}catch (Error $e) {
    echo $e->getMessage(). "\n";
}
?>

Above example will show the message  "Call to undefined function add()" for php7 and above version but in php5.x it will throw fatal error so that is big improvement of php7.

<?php
try{
  $obj = new People();//trying to create object of not existence class
}catch (Error $e) {
    echo $e->getMessage(). "\n";
}
?>

So in this example output will be "Class 'People' not found "

-> Explanation and use of  TypeError class.
There are three scenarios where a TypeError may be thrown.
1. The argument type being passed to a function does not match its corresponding declared parameter type.
2. Value being returned from a function does not match the declared function return type
3. An invalid number of arguments are passed to a built-in PHP function (strict mode only)


Example of first scenario :

<?php
function add(int $num1,int $num2)
{
    return $num1+$num2;
}

try{
    add(100,'b'); //Second parameter is string but it should be int.
}catch(TypeError $e){
    echo $e->getMessage();
    
}

If you will execute it then it will throw error like "Argument 2 passed to add() must be of the type integer, string given"

Example of 2nd scenario :

<?php
/**
 * If you want to use return type of the function then you need to
 * use declare (strict_types = 1); statement at the top of the file to  support return type
 * 
 */

declare (strict_types = 1); 
function add(int $num1,float $num2): int
{
    return $num1+$num2;
}

try{
    echo add(100,2.5);
}catch(TypeError $e){
    echo $e->getMessage();
    
}

If you try to execute this program then it will throw error like : Return value of add() must be of the type integer, float returned.
You have given return type of defined function add as an integer so if this function return other than integer then program will throw TypeError exception.

Now I am going to change the return type of above function from int to float then let see the result.

<?php
/**
 * If you want to use return type of the function then you need to
 * use declare (strict_types = 1); statement at the top of the file to support return type
 * 
 */
declare (strict_types = 1);
function add(int $num1,float $num2): float
{
    return $num1+$num2;
}

try{
    echo add(100,2.5);
}catch(TypeError $e){
    echo $e->getMessage();

}

Output of this program is : 102.5

Example of third scenario :

I am trying to explain this scenario with rand php in built function.As you know this function required only two parameters min and max. Now I am going to pass three parameters in this function without using strict_types.
<?php
try{
    echo rand(1,2,3);
}catch(TypeError $e){
    echo $e->getMessage();

}
If you try to run this program then it will throw error like : Warning: rand() expects exactly 2 parameters, 3 given in /opt/lampp/htdocs/testscript/php7/exception/typeerror.php on line 11.So this kind of error we can't show in front of the user.

So in the above example, exception  is not working so this program behave like php5.x version.So if you want to support TypeError exception then you need to add strict_types.

Use  strict_types.
<?php
declare (strict_types = 1);
try{
    echo rand(1,2,3);
}catch(TypeError $e){
    echo $e->getMessage();

}

If you try to run this program then it will show error like : rand() expects exactly 2 parameters, 3 given

Loops In PHP

Four types of loop in php:

  1. for
  2. foreach
  3. while
  4. do while

For Loop

Syntax 1:
for( Initialization ; Condition ; Increment/Decrement ){

Statement;

}
Example 1: Write a program to print value from 1 to 5.
<?php
for($initialization=1 ; $initialization<=5 ; $initialization++){
    echo $initialization."<br>";
}
?>
Output:
1
2
3
4
5

Syntax 2:
for( Initialization1 , Initalization2 ; Condition ;  Increment/Decrement ,  Increment/Decrement ){

Statement;

}
Example 2 : Write a program to print 1 to 5 as well as 5 to 1.
<?php
for($initialization1=1 , $initialization2 = 5; $initialization1<=5 ; $initialization1++ ,$initialization2-- ){
    echo $initialization1."&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$initialization2<br>";
}
?>
Output:
1     5
2     4
3     3
4     2
5     1

Syntax 3 :
Initialization;
for ( ; Condition ; Increment/Decrement ){

Statement;

}

Syntax 4 :
Initialization;
for( ; Condition ; ){

Statement;
Increment/Decrement;

}

While Loop:

Syntax 1:

 while(condition true){

statement1;

}

Example 1 :

<?php
$var = 5;
while($var!=0){
echo $var;
$var--;
}
?>

Output : 54321
Note : While loop work if and only if while condition is true.

Do While Loop:

Syntax 1:

do{

statement1;

}while(condition true)

Note : Suppose you have a situation in which you would like to execute one statement without condition and the same statement with condition then in this type of situation "do while" conditional statement is useful.

Example 1:

<?php
$var = 5;
do{
/**
* This statement will execute first time without any condition
* but next time execute with while condition.
*/
echo "value = $var<br>";
$var--;
}while($var!=0);
?>

Output :
value = 5
value = 4
value = 3
value = 2
value = 1

Operators in php

Php Operators :

There are many types of operators in php.

  1. Arithmetic Operators
  2. Comparison Operators
  3. Assignment Operators
  4. Increment/Decrement Operators
  5. Logical Operators
  6. String operators
  7. Error Control Operators
  8. Array Operators
  9. Bitwise Operators
  10. Type Operators
  11. Execution Operators
  12. Error Control Operators

1 Arithmetic Operators

+ (addition)
- ( subtraction) This operation work as a subtraction as well as negation
$a - $b ( this is the example of subtraction)
-$a ( this is the example of negation that means opposite of  $a )
* (multiplication)
% ( modulus
/ ( division)
** ( exponentiation )  ( This will work in PHP 5.6 version or later)

 Example of arithmetic operators :

<?php
$var1 = 100;
$var2 = 200;
$sum = $var1 + $var2;
$subtraction = $var2 - $var1;
$multiplication = $var1 * $var2;
$division = $var2/$var1;
$modulus = $var2%$var1;

echo "Sum  = $sum<br>";
echo "Subtraction  = $subtraction<br>";
echo "Multiplication  = $multiplication<br>";
echo "Division  = $division<br>";
echo "modulus = $modulus<br>";

?>
Output :
Sum = 300
Subtraction = 100
Multiplication = 20000
Division = 2
modulus = 0


2 Comparison Operators

==  ( Equal )
=== ( Identical )
!= (Not Equal )
!== ( Not Identical )
<> ( Not Equal )
>= ( Greater than or equal to )
<= ( Less than or equal to )
>  ( Greater than )
<  ( Less than )

Simple example of the above mentioned operators.

<?php
$var1 = 100;
$var2 = 100.00;
$var3 = 100.00;
$var4 = 50;
if($var1==$var2){
echo "Equal comparison operator<br>";
}
/**
* This condition work if and only if
*  both operands are same in value as well as data type
*  In this case $var1 and $var2 are same in value but not in data type.
*  So this condition will not work.
*/
if($var1===$var2){
echo "Identical comparison operator<br>";
}
/**
* This condition will work because $var2 and $var3 are same in value as well as data type
*/
if($var2===$var3){
echo "Identical comparison operator<br>";
}
if($var1 > 50){
echo "Greater than operator<br>";
}
if($var1 < 50){
echo "Less than operator<br>";
}
if($var1 >= 100){
echo "Greater than or equal operator<br>";
}
if($var1 <= 100){
echo "Less than or equal operator<br>";
}
if($var1 != $var4){
echo "Not equal operator<br>";
}
if($var1 <> $var4){
echo "Not equal operator<br>";
}
if($var1 !== $var2){
echo "Not identical operator<br>";
}
?>

Output :
Equal comparison operator
Identical comparison operator
Greater than operator
Greater than or equal operator
Less than or equal operator
Not equal operator
Not equal operator
Not identical operator


3 Assignment Operators

= ( This is assignment operator )

<?php
$a =100;
echo "Value of a = $a<br>";
$a+=100;    // $a = $a + 100;
echo "Value of a = $a<br>";
$a-=100;    //$a = $a-100
echo "Value of a = $a<br>";
$a*=100;     // $a = $a*100
echo "Value of a = $a<br>";
?>
Output :
Value of a = 100
Value of a = 200
Value of a = 100
Value of a = 10000


4 Increment/Decrement Operators

++ ( Increment Operator )
- -  ( Decrement Operator )

$a++   // $a++  and $a=$a+1 are same
$a--     // $a-- and $a=$a-1 are same

Understand with simple example.

1 )
<?php
$a = 100;
echo "Value of a = $a<br>";
/**
* Now you can increase the value of $a by 1
* using $a++( $a++ means $a=$a+1)
*/
$a++;
echo "After increment the value of a = $a<br>";
/**
* Now you can decrease the value of $a by 1
* using $a-- ( $a-- means $a=$a-1
*/
$a--;
echo "After decrement the value of a = $a<br>";
?>

Output :
Value of a = 100
After increment the value of a = 101
After decrement the value of a = 100


5 Logical Operators

There are three logical operators:
1) &&  ( And operator works on two operands  like $operand1 && $operand2)
2) ||  ( Or operator works on two operands like  $operand1 || $operand2)
3) !  ( Not operator  works on one operands like !$operand1)

Lets take a simple example to understand these all three operators.
You can copy past to check the blow code as well.

<?php

/**
 * 
 * In this block we will try to understand && logical operator
 */
$operand1=true;
$operand2=true;
if($operand1 && $operand2){  // If both are true then its work
    echo "Condition is true<br>";
}

$operand1=false;
$operand2=true;

if($operand1 && $operand2){  // If both are true then its work
    echo "If condition is true because of  both operands are true<br>";
}else{ //  If any of the operands or both operands are false then this block will work
    echo "Else block will execute because of any of the operands or both operands are false<br>";
}

/**
 * Output of the above block is below:
 * Condition is true
 * Else block will execute because of any of the operands or both operands are false
 */

/**
 * In this block we will try to understand ||  logical operator
 */

$operand1=false;
$operand2=true;

if($operand1 ||  $operand2){  // If any one operand is true then this block will work
    echo "Condition is true<br>";
}

$operand1=false;
$operand2=false;

if($operand1 || $operand2){  // If any one operand is true then this block will work
    echo 'If any one operand is true then this block will work<br>';
}else{ //  If  both operands are false then this block will work
    echo "Else block will execute because of both operands are false<br>";
}

/**
 * Output of the above block is below:
 * Condition is true
 * Else block will execute because of both operands are false
 */


/**
 * Lets take a example to understand ! (not) operator 
 */

$operand1=false;
if(!$operand1){   //  This means if not true then this block will work
    echo " This means if not true then this block will work<br>";
}

$operand1 =10;
if($operand1==10){
    echo "Operand1 value is 10<br>";
}
$operand1 =11;
if($operand1!=10){
    echo "Operand1 value is not 10<br>";
}

/**
 * Output of the above block is below:
 * This means if not true then this block will work
 * Operand1 value is 10Operand1 value is not 10
 */

Conditional Statement

Following are the  conditional statement in PHP.
1 if
2 if else
3 nested if else

Syntax  1:

if(condition){
statement;
}

Note : In the above case if condition true then statement will execute otherwise execution will skip this part.

Example :
<?php
$a =100;
if($a>=100){ // If condition true
echo "Value of a=$a";
}
?>
Output : Value of a=100;

<?php
$a =100;
if($a<100){ // In this case condition fail thats why execution skip this block
echo "Value of a=$a";
}
?>
Output : Nothing

Syntax 2:

if(condition){
statement1;
}else{
statement2;
}
Note: In the above case if condition is true then if statement will execute otherwise else statement will execute.

Example 1 :
<?php

$a=100;
if($a!=100){
echo "Satatement1 : value of a=$a";
}else{
echo "Satatement2 : value of a=$a";
}
?>

Output : Statement2 : value of a = 100

Example 2 :
<?php

$a=99;
if($a!=100){
echo "Satatement1 : value of a=$a";
}else{
echo "Satatement2 : value of a=$a";
}
?>

Output : Statement1 : value of a = 99

Syntax 3 :

if(condition){

Statement1;

}elseif(condition){

Statement2;

}elseif(condition){

statement3;

}else{

statement4

}

Note : The above statement is nested statement so there is no limit of hierarchy so according to requirement we can either increase or decrease it .In this hierarchy if you have only conditional statement then there is no need to use default statement 'else'. In this case "else" statement is optional.

Example :

<?php

$marks = 40;
if($marks>=60){

echo "First division";

}elseif($marks<60 && $marks>=40){

echo "Second division";

}elseif($marks<40 &&  $marks>=30){

echo "Third division";

}else{

echo "Fail";

}

?>

Output : Second division

Note : So finally if you have a multiple conditions then you can manage your requirement using nested 'if else statement'.