PHP как отрабатывал так и отрабатывает без типизации, так как это слабо типизированный язык и именно режим работы без типизации для него и является нормальным просто ввиду его слабой типизации. И до реально строгой типизации ему еще очень далеко, так как внутри метода можно легко поменять тип значения, что в строго-типизированных языках не реально сделать. Пока это попытка упорядочить типы хоть как то хотя бы на входе/выходе. И до появления входящих-исходящих типов на методах об этой типизации никто никогда и не думал не смотря на declare, так как толку от нее было ну как то совсем мало. Разве что для тестирования ошибок. Реально это хоть как то стало нужно после PHP 7, когда этим занялись разработчики языка. А по факту - уже после PHP8 это можно пытаться хоть как то нормально внедрять для документирования и контроля входящих/исходящих типов. Но если тенденция внедрять этот стиль становится явной, то конечно лучше уже начинать внедрять эти штуки-дрюки. Я пока для себя вижу что это удобно для документирования, так как просто нельзя задокументировать другой тип входа/выхода, если он не поддерживается логикой, что по сравнению с докблоками конечно же более надежно. По факту иметь проблемы из за типов очень редко когда приходится в PHP, именно из за слаботипизированной структуры языка. И кстати как раз после введения строгой типизации в нынешнем виде этих проблем мне кажется добавится, так как компилятор уже не отработает тип самостоятельно, а будет ждать нужный тип на входе. В принципе я наверное начну у себя это внедрять в основном из-за более надежного документирования, но на новую ступень эволюции это конечно же никак не выведет.
Declare была, а вот возможности указывать скалярные типы для аргументов появилась только в семёрке. https://www.php.net/manual/ru/migration70.new-features.php
Краткость — сестра таланта... Это тебе дает оправдание месить любой тип данных в коде, зная что умный PHP интерпретатор схавает кашу кое как ? Лови PHP: Fatal error: Uncaught TypeError: sumOfInts(): Argument #2 must be of type int, string given, called in PHP: <?php declare ( strict_types = 1 ); // Принудительный режим function sumOfInts(int ...$ints) { return array_sum($ints); } var_dump(sumOfInts(2, '3', 4.1)); я в а*уе от вас "программисты"
И как часто у тебя проблемы с типами были в пхп? Ты понимаешь вообще что это в первую очередь СЛАБО-ТИПИЗИРОВАННЫЙ язык аху...нный ты программист, а ты из него хочешь получить строгую типизацию во всей красе и еще сказать что это единственный верный вариант а все вокруг идиоты? В какую сторону тебе молиться/поклоняться? У тебя че, уровень тестостерона растет после того как ты начинаешь себя выпячивать? Давай завязывай.
@MouseZver А причём тут? В пятёрках так было нельзя, этот листинг это никак не опровергает. Как по мне, это шикарно, что без этого strict это сработает. Ну может когда-нибудь я напишу код, где действительно будет суперважно, чтоб пых не привёл типы к нужному, пока я с такой ситуацией не сталкивался. Поскольку в строгом режиме empty("0") === true, несмотря на строгий режим, я вообще в нём смысла не вижу.
Действительно... вот и я думаю - с какого ты перепрыгнул на тему pack/unpack значений ( PHP 5.6 ), когда речь шла про строгую типизацию во всех версиях PHP Всегда, прикинь ? И любой "программист", кто не поленится включить полное отображение всех своих косяков и ошибок, увидит. Но у тебя в духе "е6ать-копать": - Ааа... PHP слабо типизированный ! Ну и по*уй, будем трахаться как попало. Поэтому из этих
Соболезную. Какой же ты рукожоп... О процессор и оператива! Да помогите этому несчастному озарить свой разум.
Бедняга. Думаю для тебя срать постами это достояние. Ну давай, напрягай место. Смешно как ты пыжишься. Где я могу купить билет на следующее твое выступление "Я - король PHP. Строго-типизированный PHP и точка. Вы все го...но"? А че, серьезно, на ютубе ты был бы в топах. Подумай.
Спойлер: Короче Пирожки горячие, сдобные, пышные... Налетай ! только что с горячего батхерта, говнокодера @musicman3
Указывать скалярные типы параметров появились в 7 версии, до 7 нельзя было написать int $arg в параметрах. По-моему, в 5.3 стало можно писать класс/интерфейс и array. И про какую тогда строгую типизацию может идти речь?
Не сидим. Но и бросаться в строгую типизацию только потому, что она появилась в языке, не стоит. И говорить, что если dictrict не включён, то это говнокод. В конце концов, от динамической типизации, слава Богу, отходить не собираются, возможность указания нескольких типов тому в подтверждение. Для меня именно отсутствие строгой типизации (ну или возможность её не включать) - главный кайф в PHP и JS по сравнению с другими языками. Я так же люблю магию в PHP, создание экземпляров классов из строки (чего, к примеру, в Java избегают, хотя она тоже так умеет - философия строгой типизации), вообще все эти прикольные, хотя и не явные штуки.
Это твой окончательный аргумент и будем продолжать давать мега советы говнокодинга на этом форуме ? по примеру поста: https://php.ru/forum/threads/kak-poluchit-znachenie-iz-takoj-stroki.94904/#post-647534 Ой.. Это кто там из-за угла тявкает ? Внимание значит тебе не уделяют... огнетушитель ща вставлю
Имелось в виду, что строгая типизация помогает избежать ошибок в первую очередь юным падаванам, где Вы там обращение к себе высмотрели или восхваление какое, я хз. Остальное под спойлером, ибо оффтоп. Спойлер Своего "Спектрума" у меня не было, а в гостях много не напрограммируешь. Потому спаял в КЮТ'е "Специалист" (конечно, попроще, чем "Спектрум", i8080 (точнее, его советский аналог КР580ВМ80А, чёрно-белый графоний)). А так-то и на Россию по программированию в 93-м катался, и на ЛШЮП как-то выиграл конкурс, в котором надо было угадать три призовых места, поставив себя на второе. Не будем возрастом меряться, это не наша заслуга, а родителей всё-таки )
О, свой человек. Вижу что в теме. Мое почтение. Вероятно я не так понял контекст с падаваном, но Вы разъяснили и все стало по местам. Думаю мы как взрослые люди друг друга поймем и обид не будет.
В общем теперь я должен стать на ступень выше эволюции всего то за несколько дней. То бишь перевел все 76 классов на строгую типизацию. Для этого мне понадобились некие скрытые знания, и теперь я вероятно маг нового уровня. А теперь по делу. Минусы: Теперь стало гораздо больше проблем с типами чем раньше, так как все типы теперь контролируются вручную. То есть прошу заметить - проблем не меньше, а больше. Где-то к примеру вместо int я дал на вход string, и тут же вылазит ошибка. Я должен сам это контролировать. Т.е. до внедрения строгой типизации проблем с типами не было вообще, ну или очень редко.... Сейчас же мы всю работу с типами делаем вместо компилятора сами. Но в целом можно привыкнуть и после того как проект будет переведен на строгую типизацию, то написание нового кода не должно быть прямо таки сложным. Выдаст ошибку, и правишь как нужно тип. Т.е. добавятся ошибки по типам, которые нужно учитывать. Плюсы: О них я говорил выше. Прежде всего это точная документация. Теперь нельзя перепутать типы параметров на функциях и записать не тот тип в документацию. Если тип окажется не верным, то выдаст ошибку. Таким образом документация четко соответствует типам, что имеет явное преимущество перед доблоками. Теперь всегда можно в IDE через документацию глянуть какие типы на входах/выходах и быть уверенным в этих значениях, в отличие от докблоков. В принципе я только из-за этого и взялся за эти типы. Кому не нужна документация на методы, то и смысла нет в строгой типизации. Но простите, где же моя новая ступень эволюции? Эй, кто подскажет? Я не ощущаю...
Тем не менее спасибо и @MouseZver, так как тема из json перешла на типизацию, а это натолкнуло меня применить ее для документирования. Какой бы срач не был, но в нем есть и хорошее зерно.
Просто посмотри как это выглядит, программируя объектно-ориентированным стилем PHP: <?php declare ( strict_types = 1 ); namespace Nouvu\Web\Components\Security\Core\User; use Symfony\Component\Security\Core\User\UserProviderInterface; use Symfony\Component\Security\Core\User\UserInterface; use Symfony\Component\Security\Core\Exception\UserNotFoundException; use Symfony\Component\Security\Core\Exception\UnsupportedUserException; use Nouvu\Web\Foundation\Application AS App; use Nouvu\Resources\Entity\User; class DatabaseUserProvider implements UserProviderInterface { public function __construct ( private App $app ) { } public function loadUserByUsername( string $username ): User { return $this -> getUser( $username ); } /* public function loadUserByIdentifier( ... ): User { } */ private function getUser( string $username ): User { $DatabaseRequestInterface = $this -> app -> repository -> get( 'query.database.select.users_username|email' )( name: $username ); if ( $DatabaseRequestInterface -> count() ) { $user = new User; $this -> app -> repository -> get( 'auth.entity.user' ) -> call( $user, ...$DatabaseRequestInterface -> get( $DatabaseRequestInterface :: FETCH_ASSOC ) ); return $user; } $exception = new UserNotFoundException( sprintf ( 'Username \'%s\' not found in the database.', $username ) ); $exception -> setUsername( $username ); throw $exception; } public function refreshUser( UserInterface $user ): User { if ( $user instanceof User ) { return $this -> getUser( $user -> getUsername() ); } throw new UnsupportedUserException( sprintf ( 'Instances of \'%s\' are not supported.', $user :: class ) ); } public function supportsClass( string $class ): bool { return User :: class === $class; } } --- Добавлено --- PHP: <?php declare ( strict_types = 1 ); namespace Nouvu\Container; use Psr\Container\ContainerInterface; use Closure; final class Container implements ContainerInterface { private array $container = []; public function set( string $name, Closure $closure ): void { $this -> container[$name] = $closure; } public function get( string $name ): mixed { $this -> has( $name ) ?: throw new ContainerException( $name ); if ( $this -> container[$name] instanceof Closure ) { $this -> container[$name] = $this -> container[$name]( $this ); } return $this -> container[$name]; } public function has( string $name ): bool { return isset ( $this -> container[$name] ) || array_key_exists ( $name, $this -> container ); } public function make( string $name, array $params = [] ): mixed { if ( ! $this -> has( $name ) ) { $this -> set( $name, fn( ContainerInterface $ContainerInterface ): mixed => new $name( ...$params ) ); } return $this -> get( $name ); } }
Для сравнения из моего: PHP: <?php /* =-=-=-= Copyright © 2018 eMarket =-=-=-= | GNU GENERAL PUBLIC LICENSE v.3.0 | | https://github.com/musicman3/eMarket | =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */ declare(strict_types=1); namespace eMarket\Core; use eMarket\Core\{ Pdo, Settings, Valid }; use \eMarket\Catalog\{ Cart }; /** * Class for user authorization * * @package Core * @author eMarket Team * @copyright © 2018 eMarket * @license GNU GPL v.3.0 * */ class Authorize { public static $customer; public static array $csrf_token = []; /** * Constructor * */ public function __construct() { $exceptions = FALSE; if (strrpos(Valid::inSERVER('REQUEST_URI'), 'controller/admin/blanks/')) { $exceptions = 'blanks'; } if (Settings::path() == 'admin' && Valid::inGET('route') != 'login' && !$exceptions) { session_start(); $this->csrfVerification(); $this->admin(); } if (Settings::path() == 'catalog' && !$exceptions) { session_start(); $this->csrfVerification(); $this->catalog(); new Cart(); } if (Settings::path() == 'install' && !$this->installVerify()) { exit; } } /** * Checking for install * Thanks to alexanderpas (https://github.com/alexanderpas) * * @return bool TRUE/FALSE */ private function installVerify(): bool { if (file_exists(getenv('DOCUMENT_ROOT') . '/storage/configure/configure.php') && file_exists(getenv('DOCUMENT_ROOT') . '/.htaccess')) { return FALSE; } return TRUE; } /** * CSRF Token * * @return string CSRF token */ public static function csrfToken(): string { if (!isset(self::$csrf_token[Settings::path()])) { self::$csrf_token[Settings::path()] = Func::getToken(32); $_SESSION['csrf_token_' . Settings::path()] = self::$csrf_token[Settings::path()]; } return self::$csrf_token[Settings::path()]; } /** * CSRF Verification * */ private function csrfVerification(): void { if (Valid::isPOST()) { if (!Valid::inPOST('csrf_token') || Valid::inPOST('csrf_token') != $_SESSION['csrf_token_' . Settings::path()]) { exit; } } if (Valid::isPostJson()) { if (!Valid::inPostJson('csrf_token') || Valid::inPostJson('csrf_token') != $_SESSION['csrf_token_' . Settings::path()]) { exit; } } } /** * Demo mode init * */ private function demoModeInit(): void { if (isset($_SESSION['login'])) { $staff_permission = Pdo::getValue("SELECT permission FROM " . TABLE_ADMINISTRATORS . " WHERE login=?", [$_SESSION['login']]); if ($staff_permission != 'admin') { $mode = Pdo::getValue("SELECT mode FROM " . TABLE_STAFF_MANAGER . " WHERE id=?", [$staff_permission]); if ($mode == 1) { Valid::$demo_mode = TRUE; } } } } /** * Dashboard check * */ private function dashboardCheck(): void { if (isset($_SESSION['login'])) { $staff_permission = Pdo::getValue("SELECT permission FROM " . TABLE_ADMINISTRATORS . " WHERE login=?", [$_SESSION['login']]); if ($staff_permission != 'admin') { $staff_data = json_decode(Pdo::getValue("SELECT permissions FROM " . TABLE_STAFF_MANAGER . " WHERE id=?", [$staff_permission]), 1); $count = 0; foreach ($staff_data as $value) { if ($value == '?route=dashboard') { $count++; } } if ($count == 0) { unset($_SESSION['login']); unset($_SESSION['pass']); header('Location: ?route=login'); } } } } /** * Session authorization for Admin Panel * * @return bool TRUE */ private function admin(): bool { $this->demoModeInit(); $this->dashboardCheck(); if (isset($_SESSION['session_start']) && (time() - $_SESSION['session_start']) / 60 > Settings::sessionExprTime()) { unset($_SESSION['login']); unset($_SESSION['pass']); unset($_SESSION['session_start']); $_SESSION['session_page'] = Valid::inSERVER('REQUEST_URI'); header('Location: ?route=login'); exit; } $_SESSION['session_start'] = time(); if (!isset($_SESSION['login'])) { unset($_SESSION['login']); unset($_SESSION['pass']); $_SESSION['session_page'] = Valid::inSERVER('REQUEST_URI'); header('Location: ?route=login'); exit; } elseif (isset($_SESSION['login']) && isset($_SESSION['pass'])) { $_SESSION['DEFAULT_LANGUAGE'] = Pdo::getValue("SELECT language FROM " . TABLE_ADMINISTRATORS . " WHERE login=? AND password=?", [ $_SESSION['login'], $_SESSION['pass'] ]); } else { $_SESSION['DEFAULT_LANGUAGE'] = Settings::basicSettings('primary_language'); } return TRUE; } /** * Session authorization for Catalog * * @return bool TRUE|FALSE */ private function catalog(): bool { if (isset($_SESSION['email_customer'])) { $customer_data = Pdo::getAssoc("SELECT * FROM " . TABLE_CUSTOMERS . " WHERE email=?", [$_SESSION['email_customer']])[0]; } else { $customer_data['status'] = 0; } if (isset($_SESSION['customer_session_start']) && (time() - $_SESSION['customer_session_start']) / 60 > Settings::sessionExprTime() || $customer_data['status'] == 0) { unset($_SESSION['password_customer']); unset($_SESSION['email_customer']); unset($_SESSION['customer_session_start']); return FALSE; } $_SESSION['customer_session_start'] = time(); if (!isset($_SESSION['email_customer'])) { self::$customer = FALSE; } else { self::$customer = $customer_data; } return TRUE; } /** * Password hashing * * @param string Password * @return string $password Hash */ public static function passwordHash(string $password): string { if (HASH_METHOD == 'PASSWORD_DEFAULT') { $options = ['cost' => 10]; $METHOD = PASSWORD_DEFAULT; } if (HASH_METHOD == 'PASSWORD_BCRYPT') { $options = ['cost' => 10]; $METHOD = PASSWORD_BCRYPT; } if (HASH_METHOD == 'PASSWORD_ARGON2I') { $options = ['time_cost' => 2]; $METHOD = PASSWORD_ARGON2I; } $password_hash = password_hash($password, $METHOD, $options); return $password_hash; } } Те же яйца только в профиль. В целом уже перепилил все, так что назад дороги нет. Для доков удобно конечно, но в целом тот еще гемор. Да и можно кстати тебе удобнее сделать USE через массив (особенно когда много по одному пути), но это дело вкуса: PHP: //Было use Symfony\Component\Security\Core\User\UserProviderInterface; use Symfony\Component\Security\Core\User\UserInterface; use Symfony\Component\Security\Core\Exception\UserNotFoundException; use Symfony\Component\Security\Core\Exception\UnsupportedUserException; //Стало use Symfony\Component\Security\Core\User\{ UserProviderInterface, UserInterface }; use Symfony\Component\Security\Core\Exception\{ UserNotFoundException, UnsupportedUserException }; Комментов тоже считай нет для IDE по докблокам (описание класса и методов). Но основное можно взять как раз из типизации. У каждого свой стиль. Нормально так вроде бы. Надеюсь в обсиралово не перерастем.
Единственный момент этой фигни, это сокращение строк, но дело привычки. PHP: use Symfony\Component\HttpFoundation\{ Request, Response }; use Nouvu\Web\View\Builder\Content; use Nouvu\Web\View\Repository\{ CommitRepository, HeadRepository, TitleRepository }; use Nouvu\Web\Component\Config\Repository; отдельная история