Certyfikat ZendPHP

Funkcje

Funkcje to pakiety kodu, których można użyć do wykonania sekwencji instrukcji. W funkcji można użyć dowolnego poprawnego kodu, w tym wywołań innych funkcji i klas. W PHP nazwy funkcji nie rozróżniają wielkości liter i można się do nich odwoływać przed ich zdefiniowaniem, chyba że są zdefiniowane w bloku kodu warunkowego. Funkcje mogą być wbudowane, dostarczone przez rozszerzenie lub zdefiniowane przez użytkownika. Funkcje różnią się od konstrukcji językowych.

Argumenty
Argumenty funkcji, zwane również parametrami, umożliwiają przekazywanie wartości do zakresu funkcji. Argumenty są przekazywane jako lista rozdzielana przecinkami i są oceniane od lewej do prawej.

Deklaracje typu argumentu
Możesz określić, jaki typ zmiennej może być przekazywany jako argument. Jest to przydatne, ponieważ PHP jest językiem luźno typowanym, a jeśli dokładnie określisz, jakiej zmiennej się spodziewasz, wówczas twoja funkcja będzie bardziej niezawodna, a kod łatwiejszy do odczytania. Kolejną zaletą jest to, że udzielanie podpowiedzi typu pomaga Twojemu IDE dawać bardziej znaczące wskazówki. Jeśli twoja funkcja jest wywoływana, a przekazywana zmienna jest niepoprawnego typu, wówczas PHP 7 zgłosi wyjątek TypeError. Aby określić typ argumentu, którego oczekujesz, dodaj nazwę typu przed definicją argumentu, tak jak poniżej:

< ?php
// $itemName musi być ciągiem, a $details musi być tablicą
function addToShoppingCart(string $itemName, array $details) {}
/*
$paymentObject musi być obiektem, który:
implementuje interfejs PaymentProviderInterface,
lub jest każdym dzieckiem z klasy, które to robi
*/
function requestPayment(PaymentProviderInterface $paymentObject) {}
/*
$employee musi być obiektem, który jest:
instancji klasy Employee,
lub jest każdym dzieckiem z klasy, które to robi
*/
function calculateWage(Employee $employee) {}
// $callback musi być wywoływalny
function performCalculation(callable $method) {}

Typ : Opis

Nazwa klasy lub interfejs : Parametr musi być instancją lub potomkiem określonej klasy lub interfejsu.
self : Parametr musi być instancją bieżącej klasy.
array
bool
float
int
string
iterable : Parametr musi być tablicą lub instancją przechodzącą
callable : Parametr musi być prawidłowym wywołaniem.

Uwaga Kiedy mówię o klasie "przodka", mam na myśli dowolną nadklasę twojej klasy: rodzica, rodzica rodzica i tak dalej. Podobnie używam słowa "dziecko", aby opisać dziecko, wnuka, prawnuka i tak dalej.

Nie można używać aliasów typu. Na przykład nie można użyć boolean zamiast wartości bool jako deklaracji typu; jeśli to zrobisz, PHP będzie oczekiwać wystąpienia klasy o nazwie boolean, takiej jak ta:

< ?php
function A(boolean $a) {var_dump($a);}
A(true);
// Błąd krytyczny: Uncaught TypeError: Argument 1 przekazany do A()musi być instancją typu boolean, podano boolean,

Istnieją dwa sposoby wymuszenia wskazówek typu skalarnego: przymusowy (domyślnie) i ścisły. Konfigurujesz tryb dla pliku, umieszczając dyrektywę declare na górze pliku. Wpłynie to na sposób, w jaki PHP wymusza argumenty funkcji, a także na typ zwracanej funkcji.

Uwaga : Ustawienie trybu strict odbywa się dla każdego pliku.

W trybie coercivePHP automatycznie spróbuje rzutować zmienne niewłaściwego typu na oczekiwany typ. W poniższym przykładzie skrypt wyświetla "string", ponieważ PHP po cichu rzutuje liczbę całkowitą, którą przekazujemy na ciąg
br> < ?php
function sayHello(string $name) {
echo gettype($name);
}
sayHello(100); // string

Jeśli jednak mielibyśmy określić tryb ścisły, PHP wygeneruje błąd typu, jak w tym przykładzie:

< ?php
declare(strict_types=1);
function sayHello(string $name) {
echo gettype($name);
}
sayHello(100);
/*
Błąd krytyczny: Uncaught TypeError: Argument 1 przekazany do sayHello () musi być typu
string, podana liczba całkowita,
*/

Alternatywna składnia typu zerowego

PHP 7.1 wprowadziło nowy sposób wpisywania zmiennych podpowiedzi, które mogą być zerowe. Możesz poprzedzić wskazówkę dotyczącą typu znakiem zapytania, aby wskazać, że zmienna może mieć wartość null lub określonego typu. Oto przykład:

< ?php
function myFunc(?MyObject $myObj)
{
echo "hello world";
}
// to jest dozwolone
myFunc(null);
// powoduje to błąd krytyczny: zbyt mało argumentów
myFunc();

Uwaga : Argument nie jest opcjonalny; musisz jawnie przekazać wartość null lub obiekt określonego typu.

Opcjonalne argumenty

Możesz określić wartość domyślną dla parametru, który powoduje, że staje się opcjonalny.

Uwaga : PHP 7 wyrzuci ArgumentCountError1, jeśli nie podasz wszystkich wymaganych parametrów funkcji. Można pominąć tylko przekazywanie opcjonalnych parametrów.

W poniższym przykładzie, jeśli użytkownik nie dostarczy komunikatu, funkcja zakłada, że będzie to world.

< ?php
function sayHi($message = 'world') {
echo "Hello $message";
}
sayHi();

Przeciążanie Funkcji

W innych językach programowania przeciążenie zwykle oznacza zadeklarowanie wielu funkcji o tej samej nazwie, ale o różnych ilościach i typach argumentów. PHP uważa, że przeciążenie jest sposobem na dynamiczne "tworzenie" właściwości i metod. PHP nie pozwoli ci ponownie określić tej samej nazwy funkcji. Jednak PHP pozwala na wywoływanie funkcji z różnymi argumentami i oferuje pewne funkcje umożliwiające dostęp do argumentów, za pomocą których funkcja została wywołana.

Oto trzy z tych funkcji:

Funkcja : Wartość zwracana

func_num_args () : Ile argumentów przekazano do funkcji
func_get_arg ($ num) : Numer parametru $num (zero)
func_get_args : Wszystkie parametry przekazane do funkcji jako tablica

Oto przykład pokazujący, jak funkcja może zaakceptować dowolną liczbę parametrów dowolnego rodzaju i jak można uzyskać do nich dostęp:

< ?php
function myFunc() {
foreach(func_get_args() as $arg => $value) {
echo "$arg is $value" . PHP_EOL;
}
}
myFunc('variable', 3, 'parameters');
/*
0 is variable
1 to 3
2 to paramerty
*/

Poniższy kod ilustruje niejasną różnicę między PHP 7 a PHP 5:

< ?php
function myFunc($data) {
$data = 'Changed';
echo func_get_arg(0);
}

W PHP 5 spowoduje to Variable ale w PHP 7 zmienia się to na Changed. To pokazuje, że w PHP 7, jeśli zmienisz wartość argumentu w funkcji, wówczas wartość zwrócona przez func_get_arg () będzie nową wartością, a nie wartością oryginalną

Variadics - zmienna liczba parametrów

PHP 5.6 wprowadził varaidics , które jawnie akceptują zmienną liczbę parametrów. Używając tokena na liście argumentów, określasz, że funkcja będzie akceptować zmienną liczbę parametrów. Parametry variadic są udostępniane w twojej funkcji jako tablica. W przypadku mieszania normalnych parametrów stałych ze składnią variadic parametr variadic musi być ostatnim parametrem na liście parametrów. Podręcznik PHP ma bardzo jasny przykład, który pokazuje interakcję między parametrami obowiązkowymi, opcjonalnymi i variadic:

< ?php
function parameterTypeExample($required, $optional = null,
...$variadicParams) {
printf('Required: %d; Optional: %d; number of variadic parameters:
%d'."\n",
$required, $optional, count($variadicParams));
}
f(1);
f(1, 2);
f(1, 2, 3);
f(1, 2, 3, 4);
f(1, 2, 3, 4, 5);

Dane wyjściowe:

$req: 1; $opt: 0; number of params: 0
$req: 1; $opt: 2; number of params: 0
$req: 1; $opt: 2; number of params: 1
$req: 1; $opt: 2; number of params: 2
$req: 1; $opt: 2; number of params: 3

Zauważ, że parametr variadic jest udostępniany jako zwykła tablica $params

Referencje

Domyślnie PHP przekazuje argumenty do funkcji według wartości, ale możliwe jest przekazanie ich przez odwołanie/referencję. Możesz to zrobić, deklarując argument jako podanie przez odwołanie, jak w tym przykładzie:

< ?php
function addOne(&$arg) {
$arg++;
}
$a = 0;
addOne($a);
echo $a; // 1

Operator & oznacza parametr jako przekazany przez referencję. Zmiany tego parametru w funkcji zmienią zmienną przekazaną do niego. Jeśli argument funkcji nie jest zdefiniowany jako odwołanie, nie można przekazać odwołania w tym argumencie. Ten kod wygeneruje błąd krytyczny:

< ?php
function addOne($arg) {
$arg++;
}
$a = 0;
addOne(&$a); // błąd krytyczny od PHP 5.4.0
echo $a;

Funkcje zmiennych

Funkcje zmiennych pod względem koncepcji są podobne do nazw zmiennych. Najłatwiej je wyjaśnić na przykładzie składni:

< ?php
funkcja foo() {
echo "Foo";
}
$var = 'foo';
$var (); // wywołuje foo()

Widzimy, że jeśli PHP napotka nazwę zmiennej z dołączonymi nawiasami, wówczas ocenia zmienną. Następnie szuka funkcji o nazwie pasującej do tej oceny. Jeśli znajdzie pasującą funkcję, zostanie wykonana; w przeciwnym razie nastąpi normalne generowanie błędów.

Uwaga Konstrukcje językowe, takie jak widzieliśmy wcześniej, nie są funkcjami. Nie można ich używać jako funkcji zmiennych.

Możesz wywołać dowolne wywołanie jako funkcję zmiennej.

Wartości zwracane

Użycie instrukcji return zapobiegnie dalszemu wykonywaniu kodu w twojej funkcji. Jeśli powrócisz z zakresu głównego, program się zakończy.

< ? php
return "hello";
echo "To nigdy nie jest uruchamiane";

PHP zwróci NULL, jeśli nie określisz wartości zwracanej dla funkcji za pomocą słowa kluczowego return. W sekcji "Generatory" zajmujemy się słowem kluczowym yieldi. Są one wystarczająco podobne, aby wspomnieć o nich tutaj, ale na tyle ważne, aby mieć własną sekcję później. Generatory pozwalają napisać funkcję, która wygeneruje kolejne elementy tablicy, które można iterować bez konieczności przechowywania całego zestawu danych w pamięci. Na końcu uzyskanej listy wartości generator może opcjonalnie zwrócić wartość końcową. W PHP 7 możemy określić, jakiego rodzaju zmiennej oczekujemy zwrócić.

Deklaracje typu zwrotu

Wcześniej sprawdziliśmy, jak można zadeklarować, jaki typ zmiennej będą argumentami funkcji. Możesz także określić, jaki typ zmiennej zwróci funkcja. Aby to zrobić, umieść dwukropek i nazwę typu za nawiasami parametrycznymi. Te same typy są dostępne dla typów zwracanych, które można określić dla argumentów. Spójrzmy na przykład:

< ?php
function getFullName(string $firstName, string $lastName): string {
return 123;
}
$name = getFullName('Mary', 'Moon');
echo gettype($name); // string

Ponieważ PHP jest domyślnie w trybie przymusu, po powrocie z funkcji konwertuje liczbę całkowitą 123 na ciąg znaków. Gdybyśmy zadeklarowali tryb ścisły, wówczas PHP wygenerowałoby błąd TypeError, tak jak to zrobiliśmy, gdy patrzyliśmy na deklaracje typu argumentu.

Uwaga : Nie można określić trybu ścisłego tylko dla jednej deklaracji typu zwracanego lub typu argumentu. Jeśli określisz tryb ścisły, wpłynie to na oba

Zwracanie Void

Jeśli funkcja zwróci null, możesz określić, że zwróci "void" (PHP 7.1+), jak w tym przykładzie:

< ?php
function sayHello(): void {
echo "Hello World";
}
// Witaj świecie
sayWorld ();

Uwaga : Próba określenia, że zwracana będzie wartość null, spowoduje błąd krytyczny.

Zwracanie przez odniesienie

Można zadeklarować funkcję, aby zwracała odwołanie do zmiennej, a nie jej kopię. Podręcznik PHP zauważa, że nie powinieneś tego robić jako optymalizację wydajności, a raczej tylko wtedy, gdy masz ku temu ważny powód techniczny. Aby zadeklarować funkcję jako return przez referencję, umieść operator & przed jej nazwa:

< ?php
function &getValue () {…}
Następnie, wywołując funkcję, umieszczasz również operatora przed wywołaniem:

$myValue = &getValue ();

Po tym wywołaniu zmienna $myValue będzie zawierać odwołanie do zmiennej zwracanej przez funkcję getValue().

Uwaga: Zwróć uwagę na różnicę między zwracaniem przez referencję (co jest dozwolone) a przekazywaniem argumentu przez referencję w czasie wykonywania (co nie jest). Sama funkcja musi zwrócić zmienną. Jeśli spróbujesz zwrócić, na przykład, liczbę liczbową, taką jak 1, zostanie wygenerowany błąd czasu wykonywania. Dwa przypadki użycia to wzorzec fabryczny i uzyskiwanie zasobu, takiego jak uchwyt pliku lub połączenie z bazą danych.

Zmienny zakres funkcji

Podobnie jak w innych językach, zakres zmiennej PHP jest kontekstem, w którym została zdefiniowana. PHP ma trzy poziomy zasięgu - globalny, funkcji i klasy. Za każdym razem, gdy wywoływana jest funkcja, tworzony jest nowy zakres funkcji. Możesz włączyć globalne zmienne zakresu do swojej funkcji na jeden z dwóch sposobów:

< ?php
$glob = "Global variable";
function myFunction() {
global $glob; // first method
$glob = $GLOBALS['glob']; // second method
$glob = "Changed";
}
myFunction();
echo $glob; // Changed

Zauważ, że te dwie metody mają identyczny efekt, pozwalając na użycie zmiennej $glob w myFunction (), i odnoszą się do zmiennej $ glob zadeklarowanej w zakresie globalnym.

Uwaga : większość standardów kodowania zdecydowanie odradza zmienne globalne, ponieważ wprowadzają problemy podczas pisania testów, mogą wprowadzać dziwne problemy kontekstowe i utrudniają debugowanie.

Lambda i Closure

Lambda w PHP jest anonimową funkcją, którą można przechowywać jako zmienną.

< ?php
$lambda = function($a, $b) {
echo $a + $b;
};
echo gettype($lambda); // true
echo (int)is_callable($lambda); // 1
echo get_class($lambda); // Closure

Widzimy, że w PHP lambdy i closures są implementowane jako obiekty tworzone z klasy Closure. Zmienne lambda i closures mogą być używane w funkcjach, które akceptują wywołanie.

Uwaga : Możesz użyć funkcji is_callable(), aby sprawdzić, czy zmienna jest wywoływalna.

Closure w PHP jest anonimową funkcją, która hermetyzuje zmienne, aby można było z nich korzystać, gdy ich oryginalne odwołania są poza zakresem. Innym sposobem na wyrażenie tego jest stwierdzenie, że anonimowa funkcja "zamyka" zmienne w zakresie, w którym została zdefiniowana. W praktycznej składni w PHP definiujemy cosure w następujący sposób:

< ?php
$string = "Hello World!";
$closure = function() use ($string) {
echo $string;
};
$closure();

To wygląda prawie identycznie jak lambda, ale zwróć uwagę na składnię use ($ string), która występuje tuż przed rozpoczęciem bloku kodu. Efektem tego jest pobranie zmiennej string, która istnieje w tym samym zakresie zamknięcia i udostępnienie jej w ramach zamknięcia.

Uwaga : Możesz wywoływać lambdy i closures a za pomocą składni używanej do funkcji zmiennych.

W tym przykładzie lambda funkcja miała dostęp tylko do parametrów, które zostały przekazane, i nic z zakresu zawierającego nie zostałoby przekazane. Wywołanie ciągu echo $ spowoduje ostrzeżenie, ponieważ zmienna nie istnieje.

Wczesne i późne wiązanie

Istnieją dwa sposoby wiązania zmiennej: wczesna i późna. We wczesnym wiązaniu znamy wartość i typ zmiennej, zanim użyjemy jej w czasie wykonywania. Zwykle odbywa się to w jakiś statyczny sposób deklaratywny. Wartość zmiennej użytej w parametrze będzie wartością, która była w momencie zdefiniowania zamknięcia. Natomiast gdy używamy późnego wiązania, nie wiemy, jaki jest typ lub wartość zmiennej, dopóki nie wywołamy zamknięcia. PHP zmusi zmienną do określonego typu i wartości, gdy będzie musiała na niej działać. Kiedy wiąże zmienną z zamknięciem, PHP domyślnie użyje wczesnego wiązania. Jeśli chcesz użyć późnego wiązania, podczas importowania należy użyć odwołania. Wszystko to stanie się wyraźniejsze, gdy przejdziesz przez prosty przykład:

< ?php
$a = "some string";
// wczesne wiązanie (domyślnie)
$b = function() use ($a) {
echo $a;
};
$a = "Hello World";
// jakiś ciąg
$b();

W tym przypadku używamy domyślnej (wczesnej) metody wiązania do powiązania wartości $a z lambda $b. Wartość $a to "jakiś ciąg", gdy definiujemy lambda. Dlatego, gdy wywołujemy lambda, wyprowadzana jest wartość "jakiś ciąg znaków", mimo że zmieniliśmy wartość $ a po zadeklarowaniu lambda. Gdybyśmy sprecyzowali, że $a ma być użyte jako odniesienie, wówczas wynikiem byłoby "Hello World", jak poniżej:

< ?php
$a = "some string";
// późne wiązanie (referencja)
$b = function() use (&$a) {
echo $a;
};
$a = "Hello World";
// Hello World
$b();

Wiązanie zamknięć do zakresów

Kiedy tworzysz zamknięcie, "zamyka" ono bieżący zakres, więc można go uznać za związany z określonym zakresem. Klasa Closure ma dwie metody - bind i bindTo - i pozwalają one zmienić zakres, z którym związana jest zmienna:

< ?php
class Animal {
public function getClosure() {
$boundVariable = 'Animal';
return function() use ($boundVariable) {
return $this->nature . ' ' . $boundVariable;
};
}
}
class Cat extends Animal {
protected $nature = 'Awesome';
}

class Dog extends Animal {
protected $nature = 'Friendly';
}
$cat = new Cat;
$closure = $cat->getClosure();
echo $closure(); // Awesome Animal
$closure = $closure->bindTo(new Dog);
echo $closure(); // Friendly Animal

W tym kodzie należy zwrócić uwagę na dwie ważne rzeczy. Po pierwsze, powiązanie zamknięcia z innym obiektem zwraca duplikat oryginału, więc musisz przypisać wynik wywołania bindTo() do zmiennej. Po drugie, nowe zamknięcie będzie miało te same powiązane zmienne i treść, ale inny związany obiekt i zakres. W poprzednim przykładzie $ boundVariable jest duplikowane do nowego zamknięcia, gdy łączymy się z nowym obiektem.

Zamknięcia samowykonujące się

Możesz tworzyć samowykonywalne anonimowe funkcje w PHP 7, używając składni bardzo podobnej do JavaScript:

< ?php
(function() {
echo 'Self-executing anonymous function';
echo $definedInClosure = 'Variable set';
})();
var_dump(isset($definedInClosure)); // bool(false)

Należy zauważyć w tym przykładzie, że zmienna, którą definiujemy wewnątrz zamknięcia, nie jest zdefiniowana poza zakresem zamknięcia. Możesz użyć tego rodzaju struktury, aby uniknąć zanieczyszczenia globalnego zasięgu.

Callables

Callables zostały wprowadzone jako wskazówka typu dla funkcji w PHP 5.4. Są to wywołania zwrotne, które są akceptowane przez niektóre funkcje, na przykład usort (). Wywołanie dla funkcji takiej jak usort () może być jedną z następujących czynności:

•  Wbudowana anonimowa funkcja
•  Zmienna lambda lub zamknięcia
•  Ciąg znaków oznaczający funkcję PHP (ale nie konstrukcje językowe)
•  Łańcuch oznaczający funkcję zdefiniowaną przez użytkownika
•  Tablica zawierająca instancję obiektu w pierwszym elemencie, oraz nazwa ciągu funkcji, którą należy wywołać w drugim elemencie
•  Ciąg znaków zawierający nazwę metody statycznej w klasie (PHP 5.2.3+)

Uwaga Nie można używać konstrukcji języka do wywołania.


QUIZ



P1: Jakie są dane wyjściowe następującego kodu?

< ?php
declare(strict_types=1);
function multiply(float $a, float $b): int {
return $a * $b;
}
$six = multiply(2, 3);
echo gettype($six);
---------

Int
Float
Błąd krytyczny: Uncaught TypeError

P2: Niektóre funkcje PHP, takie jak echo, nie wymagają używania nawiasów podczas ich wywoływania. Czy to prawda?

---------

Tak, ponieważ można to tak nazwać: echo "cześć";
Tak, ponieważ echo to szczególny przypadek.

Nie, ponieważ echo jest konstrukcją języka, a nie funkcją. Wszystkie funkcje PHP wymagają użycia nawiasów podczas ich wywoływania.
Nie, ponieważ wszystkie funkcje PHP wymagają użycia nawiasów podczas ich wywoływania, z wyjątkiem echa, które wymaga tylko nawiasów, gdy używasz więcej niż jednego argumentu.

P3: Nie można użyć funkcji empty() jako wywołania zwrotnego dla funkcji usort ().

--------

Prawdziwe
Fałszywy

P4: Jakie są wyniki następującego kodu?

(function Hello () {
echo "Hello world!";
}) ();
----------

Nic
Witaj świecie
Komunikat o błędzie i "Hello World"
Tylko komunikat o błędzie

P5: Jakie są dane wyjściowe następującego kodu?
v < ?php
declare(strict_types=1);
function multiply(float $a, float $b): float {
return (double)$a * (double)$b;
}
$six = multiply(2, 3);
echo gettype($six);
----------

int
double
float
To generuje TypeError

P6: Jakie są wyniki następującego kodu?

< ?php
function complicated($compulsory, .$extras) {
echo "I have " . func_get_args() . " arguments";
}
complicated(1,2,3,4);
----------

1
2
4
Powoduje to błąd powiadomienia

P7: Jak odnosiłbyś się do parametru z wartością cat w poniższej funkcji?

< ?php
function complicated($compulsory, ...$extras, $animal) {
// I want to reference the variable with the value "cat"
}
complicated(1,2,3,"cat");
-----------

$animal
$extras[1]
$extras[2]
To powoduje błąd

P8: Co wygeneruje ten kod?

< ?php
if (!is_callable(function(){echo "Hello";})) {
function sayHello() {
echo "World!";
}
}
sayHello();
------------

Hello
World!
Hello World!
To powoduje błąd
P9: Co wygeneruje ten kod?

< ?php
namespace A;
function Hello() { echo __NAMESPACE__; }
namespace B;
function Hello() { echo __NAMESPACE__; }
namespace C;
\B\Hello();
------------

A
B
C
To powoduje błąd; funkcje nie mogą mieć przestrzeni nazw

P10: Co wygeneruje ten kod?

< ?php
namespace A;
$closure = function() { echo __NAMESPACE__; };
namespace B;
$closure = function() { echo __NAMESPACE__; };
namespace C;
$closure();
-------------

A
B
C
To powoduje błąd; zamknięcie nie jest zdefiniowane w przestrzeni nazw C
To powoduje błąd; funkcje i zamknięcia nie mogą mieć przestrzeni nazw


ODPOWIEDZI



• Błąd krytyczny: Uncaught TypeError

•  Nie, ponieważ echo jest konstrukcją języka, a nie funkcją. Wszystkie funkcje PHP wymagają użycia nawiasów podczas ich wywoływania.

•  PRAWDA

•  Tylko komunikat o błędzie

•  double

•  Powoduje to błąd powiadomienia

•  To powoduje błąd

•  To powoduje błąd

•  B

•  B