Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:119664 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 13547 invoked from network); 3 Mar 2023 16:30:50 -0000 Received: from unknown (HELO php-smtp4.php.net) (45.112.84.5) by pb1.pair.com with SMTP; 3 Mar 2023 16:30:50 -0000 Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 5CE8B18033A for ; Fri, 3 Mar 2023 08:30:49 -0800 (PST) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on php-smtp4.php.net X-Spam-Level: X-Spam-Status: No, score=-2.8 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_LOW, RCVD_IN_MSPIKE_H3,RCVD_IN_MSPIKE_WL,SPF_HELO_PASS,SPF_NONE, T_SCC_BODY_TEXT_LINE autolearn=no autolearn_force=no version=3.4.2 X-Spam-ASN: AS19151 66.111.4.0/24 X-Spam-Virus: No X-Envelope-From: Received: from out2-smtp.messagingengine.com (out2-smtp.messagingengine.com [66.111.4.26]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (P-256) server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Fri, 3 Mar 2023 08:30:48 -0800 (PST) Received: from compute4.internal (compute4.nyi.internal [10.202.2.44]) by mailout.nyi.internal (Postfix) with ESMTP id 8A11A5C0070 for ; Fri, 3 Mar 2023 11:30:47 -0500 (EST) Received: from imap50 ([10.202.2.100]) by compute4.internal (MEProxy); Fri, 03 Mar 2023 11:30:47 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= garfieldtech.com; h=cc:content-type:content-type:date:date:from :from:in-reply-to:in-reply-to:message-id:mime-version:references :reply-to:sender:subject:subject:to:to; s=fm1; t=1677861047; x= 1677947447; bh=GqK9ikWxkSvu11m+3P5H9PiSu5db2IyzncDkCuyRFpA=; b=B l9C47TZTaXKxbBr+7IawqlOP2E0EcuhnytEejkk1nEfwG15WJMfIHeezCdztaYkD llAJtw1sQ7YbIj2eZv2OQqii4BmcFmFJjXwURx1EAg5ElHLA3j1+D9QwuT/qWIQN UY0Peq/rSxD/LzsVC0iCrR3MAM2orrwKF1U3fzROnFjBhk3DBN4XdxnR6Z/ZsMiV 7cB5EpGOzN4gIip3FXrU9GkL7Ct/+Z6LrtnmFk2qiwb/sBUO5xtGecnMYrHawZAu 3J/6P6ca8XroQgBrgKl9FLZtsfoUDkUBrD7KzhjIrFh0FAIiaU5zU3wGw3O7uKz0 Y3JEfPAidl3k321TuesxA== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-type:content-type:date:date :feedback-id:feedback-id:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:sender:subject :subject:to:to:x-me-proxy:x-me-proxy:x-me-sender:x-me-sender :x-sasl-enc; s=fm1; t=1677861047; x=1677947447; bh=GqK9ikWxkSvu1 1m+3P5H9PiSu5db2IyzncDkCuyRFpA=; b=l0I+Q5ELLw7f9FNpUfLq2/4DiwRH4 uKB5vsWsOPC/FkIrdVucTO73wFRB29vX9tV8arQrwv/KofR1fq6k3X7RRsI4G/m3 BbmyiFa63fo2xjv0in74MMFa0ZFhag8lLpy670aJbhe6CEdCTQNjTnOHY0wT8Lmu nJjAQQpe1DHv/WBnohFXB2DZd+gpOCIJcUafFN8ZaDN4MC7x2RIaEMRfMTUzBLQy bn8VKaT+aMSDMNtW19+Qfj2m/DNnXtR0bY+s+Q1FsDWfBbk9NbfR/ASlFlRDQWLh d6aRgNZ6G87YmgTXI3gT168PH4BoNzXPfWK3j08GIWhx6sQKCxvC7RDgA== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvhedrudelledgkeefucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepofgfggfkjghffffhvffutgesthdtredtreertdenucfhrhhomhepfdfnrghr rhihucfirghrfhhivghlugdfuceolhgrrhhrhiesghgrrhhfihgvlhguthgvtghhrdgtoh hmqeenucggtffrrghtthgvrhhnpedtfedvjeegkeffveektefhkeetueekjeefteduieef geetueeffeefudeugedvveenucffohhmrghinhepjhhsohhnqdhstghhvghmrgdrohhrgh enucevlhhushhtvghrufhiiigvpedtnecurfgrrhgrmhepmhgrihhlfhhrohhmpehlrghr rhihsehgrghrfhhivghlughtvggthhdrtghomh X-ME-Proxy: Feedback-ID: i8414410d:Fastmail Received: by mailuser.nyi.internal (Postfix, from userid 501) id 53BF51700089; Fri, 3 Mar 2023 11:30:47 -0500 (EST) X-Mailer: MessagingEngine.com Webmail Interface User-Agent: Cyrus-JMAP/3.9.0-alpha0-183-gbf7d00f500-fm-20230220.001-gbf7d00f5 Mime-Version: 1.0 Message-ID: <86dc97c5-96b2-4da3-aaaf-f94a833fba70@app.fastmail.com> In-Reply-To: References: <7e08b0f9-9d30-4ead-8194-2494ecc78e2e@app.fastmail.com> Date: Fri, 03 Mar 2023 10:30:26 -0600 To: "php internals" Content-Type: text/plain Subject: Re: [PHP-DEV] RFC Idea - json_validate() validate schema From: larry@garfieldtech.com ("Larry Garfield") On Fri, Mar 3, 2023, at 6:19 AM, Jakub Zelenka wrote: >> You mean using the version from the JSON string, and allowing an >> override? Like this? >> >> > It should never allow overriding the $schema as it would go against spec so > this would be just default if $schema is not specified. Just the default > could be overridden. That sounds like it could be hard to explain why a parameter only sometimes does something... Which suggests we should take a different approach. >> new JsonSchema($schema_string, version: JsonSchema::DRAFT_4); >> > Would be probably called more JsonSchema::VERSION_DRAFT_04 but essentially > yeah I was thinking either that or something like just global constant > JSON_SCHEMA_VERSION_DRAFT_04 which is currently more convention in json > extension. I wouldn't really mind using the class constant though. Class constants FTW. > As I said my main point was that custom defined schema should contain > version in the schema - I realise that it might not be used in wild but > this is defined as SHOULD in all drafts so we should follow that > recommendation in our API design. When this is the case, there is no point > for user to explicitly pick the schema class IMO. > > Another thing to note is that we might want to introduce some sort of a > factory method or factory class instead of using constructor because as I > said before we would probably like to introduce more sources for schema > than just string in the future. It means it could be automatically > generated schema from a class so only the class name would be passed or for > convenience it could be just passed directly from the assoc array. It is > basically pointless to always convert it to string because internally it > will just decode the json string to object (stdClass) or more likely array > and parse the schema internal representation from that. If we had this, we > could maybe introduce a different schema classes as well but it would be > more invisible for users and could be just subclasses of JsonSchema or > JsonSchema would be just an interface. I'm totally fine with factory methods. I'm less enamored with a factory class, but open to discussing it. >> I see two issues there. >> >> 1. If I want to see if DRAFT_6 is available, I have to use defined()[1] >> with strings. This is fugly. >> >> > This is a good point as for class with autoloader you don't need strings. > > Maybe we could also introduce JsonSchema::VERSION_LATEST which would have > value of the last supported draft. Then you could check if draft-06 is > supported by just doing something like > > if (JsonSchema::VERSION_LATEST > JsonSchema::VERSION_DRAFT_04) { > // at lest draft 06 > } else if (JsonSchema::VERSION_LATEST > JsonSchema::VERSION_DRAFT_06) { > // at lest draft 07 > } else ... > > > We could also support string for the actual version and allowing passing > the well defined values for $schema. The it would throw exception if it's > not supported. We could even have static method to check whether version is > supported and then for example doing something like > > if (JsonSchema::isVersionSupported(" > https://json-schema.org/draft/2020-12/schema")) { ... } thinking-face.gif That could work. For simplicity someone in user space (FIG?) could release a set of constants that can be rapidly updated, but the actual PHP API is just looking at the URL. If we expect it to be a rarely-used feature, I'd be on board with that. >> 2. I don't know how to polyfill newer spec versions if I don't want to >> wait for internals to get around to adding a new version. >> > > I guess it could be possible to support custom user validators (e.g. > instances implementing JsonSchema interface if above concept is used) in > the future but it would be of course more limited. That's not something > that would happen initially but it might be good design an API with that in > mind. > > So to sum it up, maybe the rough structure could be something like > > interface JsonSchema { > const VERSION_DRAFT_04 = 1; > const VERSION_DRAFT_06 = 2; > const VERSION_DRAFT_07 = 3; > const VERSION_LATEST = 3; > > public function validate(array|stdClass $data): bool; > } > > class JsonSchemaForVersionDraft04 implements JsonSchema { > public function validate(array|stdClass $data): bool {} > } > > class JsonSchemaForVersionDraft06 implements JsonSchema { > public function validate(array|stdClass $data): bool {} > } > > class JsonSchemaForVersionDraft07 implements JsonSchema { > public function validate(array|stdClass $data): bool {} > } > > class JsonSchemaFactory { > public static function createFromJsonString(string $jsonString, > int|string $version = JsonSchema::VERSION_LATEST): JsonSchema {} > > public static function createFromClasl(string $className, int|string > $version = JsonSchema::VERSION_LATEST): JsonSchema {} > > public static function createFromArray(array $schemaData, int|string > $version = JsonSchema::VERSION_LATEST): JsonSchema {} > > public static function isVersionSupported(int|string $version): bool {} > } > > Just a draft of course so any ideas how to improve it are welcome. > > What do you think? Hm. So you're idea is that you'd parse the JSON string with json_decode() first, then pass that to the validator? Is that really the most performant/convenient approach? (I don't know, but I question if it is.) Thinking about it another way, I see three base primitives that are better done in C than in PHP. 1) validate(SchemaDefinition $schema_definition, $json_value): bool 2) make_schema(string $jsonSchemaString): SchemaDefinition (and possibly alternates with other typed parameters) 3) make_schema_from_class(string $className, string $version = latest available): SchemaDefinition Everything else could be done in user-space without any significant performance impact. Even 3 could technically be done in user space if SchemaDefinition had a robust API that could be populated from user space, rather than being opaque. So a major question is what level of exposed API we want the schema object to have. (I could probably argue both ways here.) (If you want to continue this real-time, I'm available in most of the PHP chat fora these days.) --Larry Garfield