Verification: a143cc29221c9be0

Php call function one time

Function Name

Same rules applied for variable names are applied for function names. That is, they can only contain letters, numbers and underscore and, should begin only with a letter or an underscore. Only exception is function names are not case-sensitive. That is, getDiscountedPrice() and GETDISCOUNTEDPRICE() are same.

Since most of the time functions perform a certain action, it’s usual that they associate a relevant verb with function name. For instance, in above example, prefix get has been used instead of naming the function as discountedPrice().

Arguments

Arguments let you pass different values to a function based on the context. For an example, getDiscountedPrice() wouldn’t be that useful if you couldn’t pass an amount and a percentage to it.

You can define default values to arguments in case that you think it’s not mandatory to pass values for them. For an example think that in your program, you had a default discount of 10% that would be used for most of the products (as shown in above function declaration). Then you can call getDiscountedPrice() as below since you have defined a default value for $percentage.

echo 'Discounted price is ' . getDiscountedPrice(100);  // Would print Discounted price is 90

However you have to be careful on what arguments are optional and their order. For an example, if you had put $percentage as the first argument then you will always have to give a value to it since second argument is mandatory. That means you can’t call the function as getDiscountedPrice( , 100). So, remember to order your arguments in the way mandatory ones come first and then come the optional ones.

Return Value

Return value is the final value you expect from a function after executing code inside it. In above case, it’s the discounted price. You may not expect return values from all the functions. For an example, you can have a function like below to print invoice headers (
tags are used to have line breaks in web browsers).

function printInvoiceHeader()
{
	echo 'Thank You! 
'; echo 'Invoice of XYZ Company
'; echo 'Date: ' . date('Y-m-d'); // Some more code may go here } printInvoiceHeader(); // This would print out the header

If you don’t specifically return a value in your function then its return value will be NULL. So, if you intended to return a value from your function then always remember to use the return statement.

$invoiceHeader = printInvoiceHeader();
var_dump($invoiceHeader); // Would show that value is NULL.

Remember that return statement is the last statement executed inside a function. Therefore it comes at the end of functions.

function getDiscountedPrice($amount, $percentage=10)
{
	return $amount-($amount*($percentage/100));
	$specialPrice = $amount-5; // This line won't be executed
}

Modifying Functions

Think that you want to remove Thank You! part from printInvoiceHeader() and move it to a footer function. You can simply remove corresponding statement and in all the places where printInvoiceHeader() is called, invoice header would be printed without Thank You!.

Ability to make a change and pass that change into many places is a great feature (Think how tedious it could be if you had hard coded invoice header everywhere). However check all the places where the function would be called and see whether change you are going to make is appropriate for all the places.

If you are adding another argument, make sure it has a default value and handle it in a way that won’t give erroneous results to already made function-calls. Otherwise you will have to edit each of those calls to accommodate the change.

Think that you wanted to give a further discount of 20 in some special occasions (amounts greater than 2000, special customer etc) then you could modify getDiscountedPrice() as below.

You would pass true for $specialDiscount when you need the special discount to take place and simply don’t pass any value where it is not necessary. In this way, you don’t have to change already defined function-calls unless the new behavior is required.

function getDiscountedPrice($amount, $percentage=10, $specialDiscount=false)
{
	$newAmount = $amount-($amount*($percentage/100));

	if ($specialDiscount) {
		$newAmount = $newAmount - 20;
	}

	return $newAmount;
}

Variable Scope

Arguments and any new variables you define inside the function exists only within the function. For instance, in above example, $amount and $newAmount won’t be available outside (unless they have been specifically defined). This lets you use same variable names for more than one function.

However if you make changes to global variables (like $_SESSION) inside a function then that change would take effect on any other place that uses the particular global variable.

get() & has()

The container implements the PSR-11 standard. That means it implements Psr\Container\ContainerInterface:

namespace Psr\Container;

interface ContainerInterface
{
    public function get($id);
    public function has($id);
}

You are encouraged to type-hint against this interface instead of the implementation (DI\Container) whenever possible. Doing so means your code is decoupled from PHP-DI and you can switch to another container anytime.

set()

You can set entries directly on the container:

$container->set('foo', 'bar');
$container->set('MyInterface', \DI\create('MyClass'));

// Use \DI\value if you need to set a closure as raw value,
// because closures are interpreted as factories by default
$container->set('myClosure', \DI\value(function() { /* ... */ }));

However it is recommended to use definition files. See the definition documentation.

make()

The container also offers a make() method. This method is defined in DI\FactoryInterface.

class GithubProfile
{
    public function __construct(ApiClient $client, $user)
    ...
}

$container->make('GithubProfile', [
    'user' => 'torvalds',
]);

The make() method works like get() except it will resolve the entry every time it is called. Depending on the type of the entry this means:

  • if the entry is an object, an new instance will be created every time
  • if the entry is a factory, the factory will be called every time
  • if the entry is an alias, the alias will be resolved every time

Please note that only the entry you ask for will be resolved every time: all the dependencies of the entry will not! That means that if the entry is an alias, the entry the alias points to will be resolved only once.

If you provide parameters to Container::make() in the second argument, and if the entry to resolve is an object to create, the parameters provided will be used for the constructor of the object, and the missing parameters will be resolved from the container.

Container::make() is useful for creating objects that should not be stored inside the container (i.e. that are not services, or that are not stateless), but that have dependencies. It is also useful if you want to override some parameters of an object's constructor.

If you need to use the make() method inside a service, or a controller, or whatever, it is recommended that you type-hint against FactoryInterface. That avoids coupling your code to the container. DI\FactoryInterface is automatically bound to DI\Container so you can inject it without any configuration.

call()

The container exposes a call() method that can invoke any PHP callable.

It offers the following additional features over using call_user_func():

  • named parameters (pass parameters indexed by name instead of position)

    $container->call(function ($foo, $bar) {
        // ...
    }, [
        'foo' => 'Hello',
        'bar' => 'World',
    ]);
    
    // Can also be useful in a micro-framework for example
    $container->call($controller, $_GET + $_POST);
  • dependency injection based on the type-hinting

    $container->call(function (Logger $logger, EntityManager $em) {
        // ...
    });
  • dependency injection based on explicit definition

    $container->call(function ($dbHost) {
        // ...
    }, [
        // Either indexed by parameter names
        'dbHost' => \DI\get('db.host'),
    ]);
    
    $container->call(function ($dbHost) {
        // ...
    }, [
        // Or not indexed
        \DI\get('db.host'),
    ]);

The best part is that you can mix all that:

$container->call(function (Logger $logger, $dbHost, $operation) {
    // ...
}, [
    'operation' => 'delete',
    'dbHost'    => \DI\get('db.host'),
]);

The call() method is particularly useful to invoke controllers, for example:

$controller = function ($name, EntityManager $em) {
    // ...
}

$container->call($controller, $_GET); // $_GET contains ['name' => 'John']

This leaves the liberty to the developer writing controllers to get request parameters and services using dependency injection.

As with make(), call() is defined in Invoker\InvokerInterface (in the PHP-DI/Invoker package) so that you can type-hint against that interface without coupling yourself to the container. Invoker\InvokerInterface is automatically bound to DI\Container so you can inject it without any configuration.

namespace Invoker;

interface InvokerInterface
{
    public function call($callable, array $parameters = []);
}

Container::call() can call any callable, that means:

  • closures
  • functions
  • object methods and static methods
  • invokable objects (objects that implement __invoke())

Additionally you can call:

  • name of invokable classes: $container->call('My\CallableClass')
  • object methods (give the class name, not an object): $container->call(['MyClass', 'someMethod'])

In both case, 'My\CallableClass' and 'MyClass' will be resolved by the container using $container->get().

That saves you from a more verbose form, for example:

$object = $container->get('My\CallableClass');
$container->call($object);

// can be written as
$container->call('My\CallableClass');

injectOn()

Sometimes you want to inject dependencies on an object that is already created.

For example, some old frameworks don't allow you to control how controllers are created. With injectOn, you can ask the container to fulfill the dependencies after the object is created.

Keep in mind it's usually always better to use get() or make() instead of injectOn(), use it only where you really have to.

Example:

class UserController extends BaseController
{
    /**
     * @Inject
     * @var SomeService
     */
    private $someService;

    public function __construct()
    {
        // The framework doesn't let us control how the controller is created, so
        // we can't use the container to create the controller
        // So we ask the container to inject dependencies
        $container->injectOn($this);

        // Now the dependencies are injected
        $this->someService->doSomething();
    }
}

As you might have guessed, you can't use constructor injection with this method. But other kind of injections (property or setter) will work, whether you use annotations or whether you configured your object in a definition file.