1
|
|
|
<?php |
2
|
|
|
if ( ! defined( 'ABSPATH' ) ) { |
3
|
|
|
exit; |
4
|
|
|
} |
5
|
|
|
|
6
|
|
|
/** |
7
|
|
|
* Provides static methods as helpers. |
8
|
|
|
* |
9
|
|
|
* @since 4.0.0 |
10
|
|
|
*/ |
11
|
|
|
class WC_Stripe_Helper { |
12
|
|
|
const LEGACY_META_NAME_FEE = 'Stripe Fee'; |
13
|
|
|
const LEGACY_META_NAME_NET = 'Net Revenue From Stripe'; |
14
|
|
|
const META_NAME_FEE = '_stripe_fee'; |
15
|
|
|
const META_NAME_NET = '_stripe_net'; |
16
|
|
|
const META_NAME_STRIPE_CURRENCY = '_stripe_currency'; |
17
|
|
|
|
18
|
|
|
/** |
19
|
|
|
* Gets the Stripe currency for order. |
20
|
|
|
* |
21
|
|
|
* @since 4.1.0 |
22
|
|
|
* @param object $order |
23
|
|
|
* @return string $currency |
24
|
|
|
*/ |
25
|
|
|
public static function get_stripe_currency( $order = null ) { |
26
|
|
|
if ( is_null( $order ) ) { |
27
|
|
|
return false; |
|
|
|
|
28
|
|
|
} |
29
|
|
|
|
30
|
|
|
$order_id = WC_Stripe_Helper::is_wc_lt( '3.0' ) ? $order->id : $order->get_id(); |
31
|
|
|
|
32
|
|
|
return WC_Stripe_Helper::is_wc_lt( '3.0' ) ? get_post_meta( $order_id, self::META_NAME_STRIPE_CURRENCY, true ) : $order->get_meta( self::META_NAME_STRIPE_CURRENCY, true ); |
33
|
|
|
} |
34
|
|
|
|
35
|
|
|
/** |
36
|
|
|
* Updates the Stripe currency for order. |
37
|
|
|
* |
38
|
|
|
* @since 4.1.0 |
39
|
|
|
* @param object $order |
40
|
|
|
* @param string $currency |
41
|
|
|
*/ |
42
|
|
View Code Duplication |
public static function update_stripe_currency( $order = null, $currency ) { |
|
|
|
|
43
|
|
|
if ( is_null( $order ) ) { |
44
|
|
|
return false; |
45
|
|
|
} |
46
|
|
|
|
47
|
|
|
$order_id = WC_Stripe_Helper::is_wc_lt( '3.0' ) ? $order->id : $order->get_id(); |
48
|
|
|
|
49
|
|
|
WC_Stripe_Helper::is_wc_lt( '3.0' ) ? update_post_meta( $order_id, self::META_NAME_STRIPE_CURRENCY, $currency ) : $order->update_meta_data( self::META_NAME_STRIPE_CURRENCY, $currency ); |
50
|
|
|
} |
51
|
|
|
|
52
|
|
|
/** |
53
|
|
|
* Gets the Stripe fee for order. With legacy check. |
54
|
|
|
* |
55
|
|
|
* @since 4.1.0 |
56
|
|
|
* @param object $order |
57
|
|
|
* @return string $amount |
58
|
|
|
*/ |
59
|
|
View Code Duplication |
public static function get_stripe_fee( $order = null ) { |
|
|
|
|
60
|
|
|
if ( is_null( $order ) ) { |
61
|
|
|
return false; |
|
|
|
|
62
|
|
|
} |
63
|
|
|
|
64
|
|
|
$order_id = WC_Stripe_Helper::is_wc_lt( '3.0' ) ? $order->id : $order->get_id(); |
65
|
|
|
|
66
|
|
|
$amount = WC_Stripe_Helper::is_wc_lt( '3.0' ) ? get_post_meta( $order_id, self::META_NAME_FEE, true ) : $order->get_meta( self::META_NAME_FEE, true ); |
67
|
|
|
|
68
|
|
|
// If not found let's check for legacy name. |
69
|
|
|
if ( empty( $amount ) ) { |
70
|
|
|
$amount = WC_Stripe_Helper::is_wc_lt( '3.0' ) ? get_post_meta( $order_id, self::LEGACY_META_NAME_FEE, true ) : $order->get_meta( self::LEGACY_META_NAME_FEE, true ); |
71
|
|
|
|
72
|
|
|
// If found update to new name. |
73
|
|
|
if ( $amount ) { |
74
|
|
|
self::update_stripe_fee( $order, $amount ); |
75
|
|
|
} |
76
|
|
|
} |
77
|
|
|
|
78
|
|
|
return $amount; |
79
|
|
|
} |
80
|
|
|
|
81
|
|
|
/** |
82
|
|
|
* Updates the Stripe fee for order. |
83
|
|
|
* |
84
|
|
|
* @since 4.1.0 |
85
|
|
|
* @param object $order |
86
|
|
|
* @param float $amount |
87
|
|
|
*/ |
88
|
|
View Code Duplication |
public static function update_stripe_fee( $order = null, $amount = 0.0 ) { |
|
|
|
|
89
|
|
|
if ( is_null( $order ) ) { |
90
|
|
|
return false; |
91
|
|
|
} |
92
|
|
|
|
93
|
|
|
$order_id = WC_Stripe_Helper::is_wc_lt( '3.0' ) ? $order->id : $order->get_id(); |
94
|
|
|
|
95
|
|
|
WC_Stripe_Helper::is_wc_lt( '3.0' ) ? update_post_meta( $order_id, self::META_NAME_FEE, $amount ) : $order->update_meta_data( self::META_NAME_FEE, $amount ); |
96
|
|
|
} |
97
|
|
|
|
98
|
|
|
/** |
99
|
|
|
* Deletes the Stripe fee for order. |
100
|
|
|
* |
101
|
|
|
* @since 4.1.0 |
102
|
|
|
* @param object $order |
103
|
|
|
*/ |
104
|
|
|
public static function delete_stripe_fee( $order = null ) { |
105
|
|
|
if ( is_null( $order ) ) { |
106
|
|
|
return false; |
107
|
|
|
} |
108
|
|
|
|
109
|
|
|
$order_id = WC_Stripe_Helper::is_wc_lt( '3.0' ) ? $order->id : $order->get_id(); |
110
|
|
|
|
111
|
|
|
delete_post_meta( $order_id, self::META_NAME_FEE ); |
112
|
|
|
delete_post_meta( $order_id, self::LEGACY_META_NAME_FEE ); |
113
|
|
|
} |
114
|
|
|
|
115
|
|
|
/** |
116
|
|
|
* Gets the Stripe net for order. With legacy check. |
117
|
|
|
* |
118
|
|
|
* @since 4.1.0 |
119
|
|
|
* @param object $order |
120
|
|
|
* @return string $amount |
121
|
|
|
*/ |
122
|
|
View Code Duplication |
public static function get_stripe_net( $order = null ) { |
|
|
|
|
123
|
|
|
if ( is_null( $order ) ) { |
124
|
|
|
return false; |
|
|
|
|
125
|
|
|
} |
126
|
|
|
|
127
|
|
|
$order_id = WC_Stripe_Helper::is_wc_lt( '3.0' ) ? $order->id : $order->get_id(); |
128
|
|
|
|
129
|
|
|
$amount = WC_Stripe_Helper::is_wc_lt( '3.0' ) ? get_post_meta( $order_id, self::META_NAME_NET, true ) : $order->get_meta( self::META_NAME_NET, true ); |
130
|
|
|
|
131
|
|
|
// If not found let's check for legacy name. |
132
|
|
|
if ( empty( $amount ) ) { |
133
|
|
|
$amount = WC_Stripe_Helper::is_wc_lt( '3.0' ) ? get_post_meta( $order_id, self::LEGACY_META_NAME_NET, true ) : $order->get_meta( self::LEGACY_META_NAME_NET, true ); |
134
|
|
|
|
135
|
|
|
// If found update to new name. |
136
|
|
|
if ( $amount ) { |
137
|
|
|
self::update_stripe_net( $order, $amount ); |
138
|
|
|
} |
139
|
|
|
} |
140
|
|
|
|
141
|
|
|
return $amount; |
142
|
|
|
} |
143
|
|
|
|
144
|
|
|
/** |
145
|
|
|
* Updates the Stripe net for order. |
146
|
|
|
* |
147
|
|
|
* @since 4.1.0 |
148
|
|
|
* @param object $order |
149
|
|
|
* @param float $amount |
150
|
|
|
*/ |
151
|
|
View Code Duplication |
public static function update_stripe_net( $order = null, $amount = 0.0 ) { |
|
|
|
|
152
|
|
|
if ( is_null( $order ) ) { |
153
|
|
|
return false; |
154
|
|
|
} |
155
|
|
|
|
156
|
|
|
$order_id = WC_Stripe_Helper::is_wc_lt( '3.0' ) ? $order->id : $order->get_id(); |
157
|
|
|
|
158
|
|
|
WC_Stripe_Helper::is_wc_lt( '3.0' ) ? update_post_meta( $order_id, self::META_NAME_NET, $amount ) : $order->update_meta_data( self::META_NAME_NET, $amount ); |
159
|
|
|
} |
160
|
|
|
|
161
|
|
|
/** |
162
|
|
|
* Deletes the Stripe net for order. |
163
|
|
|
* |
164
|
|
|
* @since 4.1.0 |
165
|
|
|
* @param object $order |
166
|
|
|
*/ |
167
|
|
|
public static function delete_stripe_net( $order = null ) { |
168
|
|
|
if ( is_null( $order ) ) { |
169
|
|
|
return false; |
170
|
|
|
} |
171
|
|
|
|
172
|
|
|
$order_id = WC_Stripe_Helper::is_wc_lt( '3.0' ) ? $order->id : $order->get_id(); |
173
|
|
|
|
174
|
|
|
delete_post_meta( $order_id, self::META_NAME_NET ); |
175
|
|
|
delete_post_meta( $order_id, self::LEGACY_META_NAME_NET ); |
176
|
|
|
} |
177
|
|
|
|
178
|
|
|
/** |
179
|
|
|
* Get Stripe amount to pay |
180
|
|
|
* |
181
|
|
|
* @param float $total Amount due. |
182
|
|
|
* @param string $currency Accepted currency. |
183
|
|
|
* |
184
|
|
|
* @return float|int |
185
|
|
|
*/ |
186
|
|
|
public static function get_stripe_amount( $total, $currency = '' ) { |
187
|
|
|
if ( ! $currency ) { |
188
|
|
|
$currency = get_woocommerce_currency(); |
189
|
|
|
} |
190
|
|
|
|
191
|
|
|
if ( in_array( strtolower( $currency ), self::no_decimal_currencies() ) ) { |
192
|
|
|
return absint( $total ); |
193
|
|
|
} else { |
194
|
|
|
return absint( wc_format_decimal( ( (float) $total * 100 ), wc_get_price_decimals() ) ); // In cents. |
195
|
|
|
} |
196
|
|
|
} |
197
|
|
|
|
198
|
|
|
/** |
199
|
|
|
* Localize Stripe messages based on code |
200
|
|
|
* |
201
|
|
|
* @since 3.0.6 |
202
|
|
|
* @version 3.0.6 |
203
|
|
|
* @return array |
204
|
|
|
*/ |
205
|
|
|
public static function get_localized_messages() { |
206
|
|
|
return apply_filters( 'wc_stripe_localized_messages', array( |
207
|
|
|
'invalid_number' => __( 'The card number is not a valid credit card number.', 'woocommerce-gateway-stripe' ), |
208
|
|
|
'invalid_expiry_month' => __( 'The card\'s expiration month is invalid.', 'woocommerce-gateway-stripe' ), |
209
|
|
|
'invalid_expiry_year' => __( 'The card\'s expiration year is invalid.', 'woocommerce-gateway-stripe' ), |
210
|
|
|
'invalid_cvc' => __( 'The card\'s security code is invalid.', 'woocommerce-gateway-stripe' ), |
211
|
|
|
'incorrect_number' => __( 'The card number is incorrect.', 'woocommerce-gateway-stripe' ), |
212
|
|
|
'incomplete_number' => __( 'The card number is incomplete.', 'woocommerce-gateway-stripe' ), |
213
|
|
|
'incomplete_cvc' => __( 'The card\'s security code is incomplete.', 'woocommerce-gateway-stripe' ), |
214
|
|
|
'incomplete_expiry' => __( 'The card\'s expiration date is incomplete.', 'woocommerce-gateway-stripe' ), |
215
|
|
|
'expired_card' => __( 'The card has expired.', 'woocommerce-gateway-stripe' ), |
216
|
|
|
'incorrect_cvc' => __( 'The card\'s security code is incorrect.', 'woocommerce-gateway-stripe' ), |
217
|
|
|
'incorrect_zip' => __( 'The card\'s zip code failed validation.', 'woocommerce-gateway-stripe' ), |
218
|
|
|
'invalid_expiry_year_past' => __( 'The card\'s expiration year is in the past', 'woocommerce-gateway-stripe' ), |
219
|
|
|
'card_declined' => __( 'The card was declined.', 'woocommerce-gateway-stripe' ), |
220
|
|
|
'missing' => __( 'There is no card on a customer that is being charged.', 'woocommerce-gateway-stripe' ), |
221
|
|
|
'processing_error' => __( 'An error occurred while processing the card.', 'woocommerce-gateway-stripe' ), |
222
|
|
|
'invalid_request_error' => __( 'Unable to process this payment, please try again or use alternative method.', 'woocommerce-gateway-stripe' ), |
223
|
|
|
'invalid_sofort_country' => __( 'The billing country is not accepted by SOFORT. Please try another country.', 'woocommerce-gateway-stripe' ), |
224
|
|
|
) ); |
225
|
|
|
} |
226
|
|
|
|
227
|
|
|
/** |
228
|
|
|
* List of currencies supported by Stripe that has no decimals. |
229
|
|
|
* |
230
|
|
|
* @return array $currencies |
231
|
|
|
*/ |
232
|
|
|
public static function no_decimal_currencies() { |
233
|
|
|
return array( |
234
|
|
|
'bif', // Burundian Franc |
235
|
|
|
'djf', // Djiboutian Franc |
236
|
|
|
'jpy', // Japanese Yen |
237
|
|
|
'krw', // South Korean Won |
238
|
|
|
'pyg', // Paraguayan Guaraní |
239
|
|
|
'vnd', // Vietnamese Đồng |
240
|
|
|
'xaf', // Central African Cfa Franc |
241
|
|
|
'xpf', // Cfp Franc |
242
|
|
|
'clp', // Chilean Peso |
243
|
|
|
'gnf', // Guinean Franc |
244
|
|
|
'kmf', // Comorian Franc |
245
|
|
|
'mga', // Malagasy Ariary |
246
|
|
|
'rwf', // Rwandan Franc |
247
|
|
|
'vuv', // Vanuatu Vatu |
248
|
|
|
'xof', // West African Cfa Franc |
249
|
|
|
); |
250
|
|
|
} |
251
|
|
|
|
252
|
|
|
/** |
253
|
|
|
* Stripe uses smallest denomination in currencies such as cents. |
254
|
|
|
* We need to format the returned currency from Stripe into human readable form. |
255
|
|
|
* The amount is not used in any calculations so returning string is sufficient. |
256
|
|
|
* |
257
|
|
|
* @param object $balance_transaction |
258
|
|
|
* @param string $type Type of number to format |
259
|
|
|
* @return string |
260
|
|
|
*/ |
261
|
|
|
public static function format_balance_fee( $balance_transaction, $type = 'fee' ) { |
262
|
|
|
if ( ! is_object( $balance_transaction ) ) { |
263
|
|
|
return; |
264
|
|
|
} |
265
|
|
|
|
266
|
|
|
if ( in_array( strtolower( $balance_transaction->currency ), self::no_decimal_currencies() ) ) { |
267
|
|
|
if ( 'fee' === $type ) { |
268
|
|
|
return $balance_transaction->fee; |
269
|
|
|
} |
270
|
|
|
|
271
|
|
|
return $balance_transaction->net; |
272
|
|
|
} |
273
|
|
|
|
274
|
|
|
if ( 'fee' === $type ) { |
275
|
|
|
return number_format( $balance_transaction->fee / 100, 2, '.', '' ); |
276
|
|
|
} |
277
|
|
|
|
278
|
|
|
return number_format( $balance_transaction->net / 100, 2, '.', '' ); |
279
|
|
|
} |
280
|
|
|
|
281
|
|
|
/** |
282
|
|
|
* Checks Stripe minimum order value authorized per currency |
283
|
|
|
*/ |
284
|
|
|
public static function get_minimum_amount() { |
285
|
|
|
// Check order amount |
286
|
|
|
switch ( get_woocommerce_currency() ) { |
287
|
|
|
case 'USD': |
288
|
|
|
case 'CAD': |
289
|
|
|
case 'EUR': |
290
|
|
|
case 'CHF': |
291
|
|
|
case 'AUD': |
292
|
|
|
case 'SGD': |
293
|
|
|
$minimum_amount = 50; |
294
|
|
|
break; |
295
|
|
|
case 'GBP': |
296
|
|
|
$minimum_amount = 30; |
297
|
|
|
break; |
298
|
|
|
case 'DKK': |
299
|
|
|
$minimum_amount = 250; |
300
|
|
|
break; |
301
|
|
|
case 'NOK': |
302
|
|
|
case 'SEK': |
303
|
|
|
$minimum_amount = 300; |
304
|
|
|
break; |
305
|
|
|
case 'JPY': |
306
|
|
|
$minimum_amount = 5000; |
307
|
|
|
break; |
308
|
|
|
case 'MXN': |
309
|
|
|
$minimum_amount = 1000; |
310
|
|
|
break; |
311
|
|
|
case 'HKD': |
312
|
|
|
$minimum_amount = 400; |
313
|
|
|
break; |
314
|
|
|
default: |
315
|
|
|
$minimum_amount = 50; |
316
|
|
|
break; |
317
|
|
|
} |
318
|
|
|
|
319
|
|
|
return $minimum_amount; |
320
|
|
|
} |
321
|
|
|
|
322
|
|
|
/** |
323
|
|
|
* Gets all the saved setting options from a specific method. |
324
|
|
|
* If specific setting is passed, only return that. |
325
|
|
|
* |
326
|
|
|
* @since 4.0.0 |
327
|
|
|
* @version 4.0.0 |
328
|
|
|
* @param string $method The payment method to get the settings from. |
329
|
|
|
* @param string $setting The name of the setting to get. |
330
|
|
|
*/ |
331
|
|
|
public static function get_settings( $method = null, $setting = null ) { |
332
|
|
|
$all_settings = null === $method ? get_option( 'woocommerce_stripe_settings', array() ) : get_option( 'woocommerce_stripe_' . $method . '_settings', array() ); |
333
|
|
|
|
334
|
|
|
if ( null === $setting ) { |
335
|
|
|
return $all_settings; |
336
|
|
|
} |
337
|
|
|
|
338
|
|
|
return isset( $all_settings[ $setting ] ) ? $all_settings[ $setting ] : ''; |
339
|
|
|
} |
340
|
|
|
|
341
|
|
|
/** |
342
|
|
|
* Checks if Pre Orders is available. |
343
|
|
|
* |
344
|
|
|
* @since 4.1.0 |
345
|
|
|
* @return bool |
346
|
|
|
*/ |
347
|
|
|
public static function is_pre_orders_exists() { |
348
|
|
|
return class_exists( 'WC_Pre_Orders_Order' ); |
349
|
|
|
} |
350
|
|
|
|
351
|
|
|
/** |
352
|
|
|
* Check if WC version is pre 3.0. |
353
|
|
|
* |
354
|
|
|
* @todo Remove in the future. |
355
|
|
|
* @since 4.0.0 |
356
|
|
|
* @version 4.0.0 |
357
|
|
|
* @return bool |
358
|
|
|
*/ |
359
|
|
|
public static function is_pre_30() { |
360
|
|
|
error_log( 'This function has been deprecated since 4.1.11. Please use is_wc_lt( $version ) instead.' ); |
361
|
|
|
|
362
|
|
|
return self::is_wc_lt( '3.0' ); |
363
|
|
|
} |
364
|
|
|
|
365
|
|
|
/** |
366
|
|
|
* Checks if WC version is less than passed in version. |
367
|
|
|
* |
368
|
|
|
* @since 4.1.11 |
369
|
|
|
* @param string $version Version to check against. |
370
|
|
|
* @return bool |
371
|
|
|
*/ |
372
|
|
|
public static function is_wc_lt( $version ) { |
373
|
|
|
return version_compare( WC_VERSION, $version, '<' ); |
374
|
|
|
} |
375
|
|
|
|
376
|
|
|
/** |
377
|
|
|
* Gets the webhook URL for Stripe triggers. Used mainly for |
378
|
|
|
* asyncronous redirect payment methods in which statuses are |
379
|
|
|
* not immediately chargeable. |
380
|
|
|
* |
381
|
|
|
* @since 4.0.0 |
382
|
|
|
* @version 4.0.0 |
383
|
|
|
* @return string |
384
|
|
|
*/ |
385
|
|
|
public static function get_webhook_url() { |
386
|
|
|
return add_query_arg( 'wc-api', 'wc_stripe', trailingslashit( get_home_url() ) ); |
387
|
|
|
} |
388
|
|
|
|
389
|
|
|
/** |
390
|
|
|
* Gets the order by Stripe source ID. |
391
|
|
|
* |
392
|
|
|
* @since 4.0.0 |
393
|
|
|
* @version 4.0.0 |
394
|
|
|
* @param string $source_id |
395
|
|
|
*/ |
396
|
|
View Code Duplication |
public static function get_order_by_source_id( $source_id ) { |
|
|
|
|
397
|
|
|
global $wpdb; |
398
|
|
|
|
399
|
|
|
$order_id = $wpdb->get_var( $wpdb->prepare( "SELECT DISTINCT ID FROM $wpdb->posts as posts LEFT JOIN $wpdb->postmeta as meta ON posts.ID = meta.post_id WHERE meta.meta_value = %s AND meta.meta_key = %s", $source_id, '_stripe_source_id' ) ); |
400
|
|
|
|
401
|
|
|
if ( ! empty( $order_id ) ) { |
402
|
|
|
return wc_get_order( $order_id ); |
403
|
|
|
} |
404
|
|
|
|
405
|
|
|
return false; |
406
|
|
|
} |
407
|
|
|
|
408
|
|
|
/** |
409
|
|
|
* Gets the order by Stripe charge ID. |
410
|
|
|
* |
411
|
|
|
* @since 4.0.0 |
412
|
|
|
* @version 4.0.0 |
413
|
|
|
* @param string $charge_id |
414
|
|
|
*/ |
415
|
|
View Code Duplication |
public static function get_order_by_charge_id( $charge_id ) { |
|
|
|
|
416
|
|
|
global $wpdb; |
417
|
|
|
|
418
|
|
|
$order_id = $wpdb->get_var( $wpdb->prepare( "SELECT DISTINCT ID FROM $wpdb->posts as posts LEFT JOIN $wpdb->postmeta as meta ON posts.ID = meta.post_id WHERE meta.meta_value = %s AND meta.meta_key = %s", $charge_id, '_transaction_id' ) ); |
419
|
|
|
|
420
|
|
|
if ( ! empty( $order_id ) ) { |
421
|
|
|
return wc_get_order( $order_id ); |
422
|
|
|
} |
423
|
|
|
|
424
|
|
|
return false; |
425
|
|
|
} |
426
|
|
|
|
427
|
|
|
/** |
428
|
|
|
* Sanitize statement descriptor text. |
429
|
|
|
* |
430
|
|
|
* Stripe requires max of 22 characters and no |
431
|
|
|
* special characters with ><"'. |
432
|
|
|
* |
433
|
|
|
* @since 4.0.0 |
434
|
|
|
* @param string $statement_descriptor |
435
|
|
|
* @return string $statement_descriptor Sanitized statement descriptor |
436
|
|
|
*/ |
437
|
|
|
public static function clean_statement_descriptor( $statement_descriptor = '' ) { |
438
|
|
|
$disallowed_characters = array( '<', '>', '"', "'" ); |
439
|
|
|
|
440
|
|
|
// Remove special characters. |
441
|
|
|
$statement_descriptor = str_replace( $disallowed_characters, '', $statement_descriptor ); |
442
|
|
|
|
443
|
|
|
$statement_descriptor = substr( trim( $statement_descriptor ), 0, 22 ); |
444
|
|
|
|
445
|
|
|
return $statement_descriptor; |
446
|
|
|
} |
447
|
|
|
} |
448
|
|
|
|
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.
Let’s take a look at an example:
Our function
my_function
expects aPost
object, and outputs the author of the post. The base classPost
returns a simple string and outputting a simple string will work just fine. However, the child classBlogPost
which is a sub-type ofPost
instead decided to return anobject
, and is therefore violating the SOLID principles. If aBlogPost
were passed tomy_function
, PHP would not complain, but ultimately fail when executing thestrtoupper
call in its body.