Function Declaration and Arguments
Basic Function Declaration
<?php
// Simple function
function greet(string $name): string
{
return "Hello, $name!";
}
echo greet('John'); // 'Hello, John!'
// Function with no return value
function logMessage(string $message): void
{
error_log(date('Y-m-d H:i:s') . ': ' . $message);
}
// Function with multiple parameters
function calculateTotal(float $price, int $quantity, float $taxRate = 0.08): float
{
$subtotal = $price * $quantity;
$tax = $subtotal * $taxRate;
return $subtotal + $tax;
}
// Using default parameter
echo calculateTotal(29.99, 3); // Uses default tax rate 0.08
echo calculateTotal(29.99, 3, 0.1); // Custom tax rate 0.1
Parameter Types
<?php
// Required parameters
function createUser(string $email, string $password): int
{
// $email and $password are required
return insertUser($email, $password);
}
// Default parameters (must come after required)
function formatPrice(float $price, string $currency = 'USD', int $decimals = 2): string
{
return number_format($price, $decimals, '.', '', $currency);
}
// Nullable parameters
function findProduct(int $id, bool $includeDeleted = false): ?Product
{
$product = $this->productRepository->getById($id);
if (!$product && !$includeDeleted) {
return null; // Can return null
}
return $product;
}
// Type declarations
function processData(
string $input,
int $maxRetries = 3,
float $timeout = 30.0,
bool $strict = false
): array {
// All parameters are type-checked
return ['processed' => true];
}
Parameter Ordering Rules
<?php
// CORRECT: Required -> Default -> Variadic
function correct(
string $required, // 1. Required first
string $withDefault = 'x', // 2. Then defaults
string ...$variadic // 3. Variadic last
): void {
// ...
}
// WRONG: Default before required
// function wrong(string $withDefault = 'x', string $required): void {}
// Fatal error!
// Named parameters (PHP 8.0+)
function createUser(
string $email,
string $name,
string $role = 'customer',
bool $active = true
): User {
// ...
}
// Can skip defaults and pass in any order
createUser(
email: 'user@example.com',
name: 'John Doe',
active: false // Skip $role, use default
);
Variable Scope in Functions
<?php
$globalConfig = ['tax_rate' => 0.08];
function getTaxRate(): float
{
global $globalConfig;
return $globalConfig['tax_rate'];
}
// Better: pass as parameter
function getTaxRate(array $config): float
{
return $config['tax_rate'] ?? 0.08;
}
// Best: use a class
class TaxCalculator
{
public function __construct(
private float $taxRate
) {}
public function calculate(float $price): float
{
return $price * (1 + $this->taxRate);
}
}
Key Takeaway
Always type-declare function parameters and return types. Default parameters must come after required ones. PHP 8 named arguments allow skipping defaults and passing arguments in any order.
Return Types and Variadic Functions
Return Types
<?php
// Explicit return types (recommended)
function getProductName(int $id): string
{
return 'Widget';
}
function calculateTax(float $price): float
{
return $price * 0.08;
}
function findById(int $id): ?Product // Nullable return type
{
return $this->repository->getById($id);
}
function getProductIds(): array
{
return [1, 2, 3, 4, 5];
}
// Return type declarations
function getData(): array
{
return [
'name' => 'Widget',
'price' => 29.99
];
}
// Never return type (PHP 8.1+)
function throwError(string $message): never
{
throw new \Exception($message);
}
// Union return types (PHP 8.0+)
function getValue(string $key): int|string|bool
{
return match($key) {
'id' => 1,
'name' => 'Widget',
'active' => true
};
}
Variadic Functions (...)
<?php
// Accept variable number of arguments
function sum(int ...$numbers): int
{
return array_sum($numbers);
}
echo sum(1, 2, 3); // 6
echo sum(1, 2, 3, 4, 5); // 15
// Variadic with other parameters
function createProduct(string $name, float $price, string ...$tags): array
{
return [
'name' => $name,
'price' => $price,
'tags' => $tags
];
}
$product = createProduct('Widget', 29.99, 'sale', 'new', 'featured');
// ['name' => 'Widget', 'price' => 29.99, 'tags' => ['sale', 'new', 'featured']]
// Spread operator (unpacking arrays)
$prices = [10, 20, 30];
echo sum(...$prices); // Same as sum(10, 20, 30)
// Practical example: logging
function logMessages(string $level, string ...$messages): void
{
foreach ($messages as $message) {
error_log("[$level] $message");
}
}
logMessages('ERROR', 'Failed to save', 'Database timeout', 'Connection lost');
Named Arguments (PHP 8.0+)
<?php
// Traditional positional arguments
function createUser(
string $email,
string $name,
string $role = 'customer',
bool $active = true,
?string $phone = null
): User {
// ...
}
// Must pass all arguments in order, even defaults
createUser('user@example.com', 'John', 'admin', true, null);
// Named arguments (PHP 8.0+):
// Can skip defaults, pass in any order
createUser(
email: 'user@example.com',
name: 'John',
phone: '555-1234',
role: 'admin'
// $active skipped, uses default true
);
// Useful with functions that have many optional params
html_entity_decode(
$encoded,
flags: ENT_QUOTES | ENT_HTML5,
encoding: 'UTF-8'
);
// Array unpacking with named arguments
$config = [
'email' => 'user@example.com',
'name' => 'John',
'role' => 'admin'
];
createUser(...$config);
Closures and Anonymous Functions
<?php
// Anonymous function assigned to variable
$double = function (int $x): int {
return $x * 2;
};
echo $double(5); // 10
// Arrow functions (PHP 7.4+)
$triple = fn(int $x): int => $x * 3;
echo $triple(5); // 15
// Closures with use keyword
function createMultiplier(float $factor): Closure
{
return fn(float $number): float => $number * $factor;
}
$double = createMultiplier(2);
$triple = createMultiplier(3);
echo $double(10); // 20
echo $triple(10); // 30
// Callback functions
$prices = [10, 20, 30, 40, 50];
$filtered = array_filter($prices, fn($p) => $p > 25);
// [30, 40, 50]
$mapped = array_map(fn($p) => $p * 1.1, $prices);
// [11, 22, 33, 44, 55]
Key Takeaway
Always declare return types. Use ?Type for nullable returns. Variadic functions accept unlimited arguments. PHP 8 named arguments make functions with many optional parameters much cleaner.
Functions in Magento Context
Magento Function Patterns
<?php
namespace Vendor\Module\Helper;
class ProductHelper
{
// Constructor with typed parameters
public function __construct(
private \Magento\Catalog\Model\ProductFactory $productFactory,
private \Magento\Catalog\Api\ProductRepositoryInterface $productRepo,
private \Magento\Framework\Logger\Monolog $logger
) {}
// Method with strict types
public function formatPrice(float $price, string $currency = 'USD'): string
{
return number_format($price, 2) . ' ' . $currency;
}
// Nullable return type
public function findProductBySku(string $sku): ?\Magento\Catalog\Api\Data\ProductInterface
{
try {
return $this->productRepo->get($sku);
} catch (\Magento\Framework\Exception\NoSuchEntityException $e) {
$this->logger->warning("Product not found: $sku");
return null;
}
}
// Array return type
public function getProductList(int $categoryId, int $page = 1, int $pageSize = 20): array
{
// Returns array of products
return [
'items' => [],
'total' => 0,
'page' => $page,
'page_size' => $pageSize
];
}
// Variadic for bulk operations
public function updateProductStatus(int $status, int ...$productIds): int
{
$updated = 0;
foreach ($productIds as $id) {
$product = $this->productRepo->getById($id);
$product->setStatus($status);
$this->productRepo->save($product);
$updated++;
}
return $updated;
}
// Named arguments in practice
public function createProduct(array $data): \Magento\Catalog\Api\Data\ProductInterface
{
$product = $this->productFactory->create();
$product->setName($data['name'] ?? '');
$product->setSku($data['sku'] ?? '');
$product->setPrice($data['price'] ?? 0.0);
$product->setStatus($data['status'] ?? 1);
$this->productRepo->save($product);
return $product;
}
}
Using Functions in Magento Templates
<?php
/** @var \Vendor\Module\Helper\Data $helper */
$helper = $this->helper('Vendor\Module\Helper\Data');
// Call helper methods
$formattedPrice = $helper->formatPrice($product->getPrice());
$productUrl = $helper->getProductUrl($product->getId());
// Use closures with Magento collections
$products = $collection->filterByCallback(function ($product) {
return $product->getPrice() > 50 && $product->getStatus() === 1;
});
// Named arguments for clarity
$formattedPrice = $helper->formatPrice(
price: $product->getPrice(),
currency: $storeManager->getStore()->getCurrentCurrencyCode()
);
Key Takeaway
Magento functions should always have type declarations, use nullable types for optional returns, and follow PSR-12 coding standards. Named arguments improve readability when calling functions with many optional parameters.
Quiz
1. What is the correct order for function parameters?
2. What does the ? (nullable) return type mean?
3. What does the ... (spread) operator do in a function call?
4. What is a named argument in PHP 8?
5. What does the void return type mean?
Flashcards
Question
What is the correct parameter order in PHP functions?
Click to reveal answer
Answer
Required parameters first, then parameters with defaults, then variadic (...$args) last.
Question
What does ?string return type mean?
Click to reveal answer
Answer
The function can return either a string or null. Equivalent to string|null union type.
Question
What are named arguments in PHP 8?
Click to reveal answer
Answer
Ability to pass arguments by parameter name: createUser(email: 'a@b.com', name: 'John'). Allows skipping defaults and passing in any order.
Question
What does the ... operator do in function parameters?
Click to reveal answer
Answer
Makes the function accept a variable number of arguments as an array. Example: function sum(int ...$numbers) accepts any number of int arguments.
Question
What is the void return type?
Click to reveal answer
Answer
Indicates the function doesn't return any value. Used for side-effect functions like logging or database operations.
Question
What is the difference between arrow functions and closures?
Click to reveal answer
Answer
Arrow functions (fn() =>) are one-line functions that automatically capture variables from parent scope. Closures require explicit 'use' keyword to import variables.
Question
How do you type-declare a function that returns an array?
Click to reveal answer
Answer
Use array return type: function getProducts(): array { return [...]; }. For specific structures, use PHPDoc comments.
Question
What is the never return type (PHP 8.1)?
Click to reveal answer
Answer
Indicates the function never returns normally - it always throws an exception or terminates. Example: function throwError(): never { throw new Exception(); }
Revision Notes
Key Takeaways
- 1. Always declare parameter types and return types for functions
- 2. Required parameters must come before default parameters
- 3. Variadic parameters (...$args) accept unlimited arguments
- 4. PHP 8 named arguments allow skipping defaults and passing in any order
- 5. Use ?Type for nullable return types
- 6. void return type means no value is returned
- 7. Arrow functions (fn() =>) automatically capture parent scope variables
Interview Tips
- • Explain parameter ordering rules (required, default, variadic)
- • Describe named arguments and their benefits
- • Know the difference between arrow functions and closures
- • Understand when to use nullable return types
- • Be able to write functions following Magento coding standards
Cheat Sheet
PHP Functions Cheat Sheet
Basic Syntax:
function name(Type $param): ReturnType {
// body
}
Parameter Types:
function example(
string $required, // Required
string $default = 'x', // Default
int ...$variadic // Variable args
): ?string { /* ... */ }
Return Types:
: string, : int, : float, : bool, : array, : void, : ?Type, : never
Named Arguments (PHP 8):
createUser(email: 'a@b.com', name: 'John', active: false);
Arrow Functions:
$double = fn($x) => $x * 2;
Closures:
$fn = function($x) use ($factor) { return $x * $factor; };