Projekt GNU dnes slaví 40. výročí. Přesně před čtyřiceti lety, 27. září 1983, Richard Stallman oznámil, že se chystá napsat s Unixem kompatibilní operační systém GNU (Gnu's Not Unix). Hlavní oslava a setkání hackerů probíhá ve Švýcarsku ve městě Biel/Bienne. Na programu je také přednáška Richarda Stallmana.
Byl vydán Mozilla Firefox 118.0. Přehled novinek v poznámkách k vydání, poznámkách k vydání pro firmy a na stránce věnované vývojářům. Vypíchnout je nutno automatický lokální strojový překlad webových stránek. Řešeny jsou rovněž bezpečnostní chyby. Nový Firefox 118 je již k dispozici také na Flathubu a Snapcraftu.
Byla vydána nová major verze 15.0.0 softwaru OCRmyPDF pro přidávání textové vrstvy k naskenovaným PDF dokumentům (PDF/A). Přehled novinek v poznámkách k vydání. OCRmyPDF využívá pro optické rozpoznávání znaků (OCR) engine Tesseract.
Karel Matějka zveřejnil druhé demo své chystané hry Bzzzt. Kromě verze pro Windows a macOS je dostupná i verze pro Linux. Plná verze hry má vyjít zanedlouho.
Noví Bulánci byli oficiálně vydáni. V roce 2021 bylo na Startovači na podporu vývoje této hry vybráno 7,3 miliónů Kč. Hra je zatím určena jenom pro Windows, díky Protonu ale běží také na Linuxu.
ChatGPT může vidět, slyšet a mluvit.
Upscaler je open source nástroj pro zvýšení rozlišení a vylepšení obrázků pomocí AI. Vývoj probíhá na GitLabu. Instalovat lze také z Flathubu. Stejně jako Upscayl je Upscaler postaven nad Real-ESRGAN.
GNUnet (Wikipedie) byl vydán v nové major verzi 0.20.0. Jedná se o framework pro decentralizované peer-to-peer síťování, na kterém je postavena řada aplikací.
V Dublinu o víkendu proběhla dvanáctá iterace multimediální konference Video Dev Days, kterou pravidelně pořádá nezisková organizace VideoLAN. Záznamy přednášek z prvního a druhého dne jsou dostupné na YouTube.
LibrePCB, tj. svobodný multiplatformní softwarový nástroj pro návrh desek plošných spojů (PCB), dospěl po pěti letech vývoje do verze 1.0.0. Přehled novinek v příspěvku na blogu a v aktualizované dokumentaci. Zdrojové kódy jsou k dispozici na GitHubu pod licencí GPLv3.
$a = new A();
Což je na tvrdo globální namespace - zkoušel sem čachrovat s use NS; atd. ale bez úspěchu $trida = Model::factory('JmenoTridy');A v té statické metodě factory ošéfovat co je třeba. V krajním případě tohle použiju, děkuju za návrh! Nenapadá někoho něco ještě lepšího? Nejraději bych psal:
$trida = new JmenoTridy();Ale zdá se, že tohle nemá řešení
namespace NS; class A extends \A { }Pro požadavek 2) zavolám v jádře:
... $a = new A(); ...Interpret nahraje třídu z jádra... donutit na jinou ho dokážu pouze konstruktem uses, ale pak nebude fungovat varianta, kdy nová třída neexistuje. Opravdu si začínám myslet, že to prostě nemá řešení a budu muset udělat nějaký workaround typu factoring... Díky
vymyslím si, že v jedné implementaci chci aby metoda A::X vracela jiný výsledekJak moc jiný?
při vytváření instance ve zbytku aplikace volám: $a = new A();Proč to nemůžete ve zbytku aplikace volat jinak?
vymyslím si, že v jedné implementaci chci aby metoda A::X vracela jiný výsledekJak moc jiný?
Typicky jde o customizace nějaké obecné metody. Např. metoda standardně vypisuje všechny soubory v adresáři, ale já chci v jedné implementaci, aby nevypisovala skryté (.*) - tedy zdědím, předeklaruju tu metodu, ta zavolá původní metodu a profiltruje výsledek na .*
při vytváření instance ve zbytku aplikace volám: $a = new A();Proč to nemůžete ve zbytku aplikace volat jinak?
Ne včechna užití té třídy jsou napsaná mnou - využívám framework.
Před chvílí sem s kolegou vykoumal řešení, které mi příjde akceptovatelné: core třída i ta implementační budou mít jméno s nějakým prefixem a v autoloaderu zařídím vedle require příslušného souboru také vytvoření aliasu třídy na "bezprefixový zápis". Např.
// deklaruju core v souboru $core_prefix/A.php class Core_A {}; // deklaruju změněnou třídu v souboru $implementacni_prefix/A.php class Implementace_A extends Core_A {} // v běžném kódu používám $a = new A(); // popř. class B extends A {} // v autoloaderu podle jména třídy najdu správný include require_once($classname); class_alias($prefix.$classname, $classname);Nic lepšího asi nevymyslím
Např. metoda standardně vypisuje všechny soubory v adresáři, ale já chci v jedné implementaci, aby nevypisovala skryté (.*) - tedy zdědím, předeklaruju tu metodu, ta zavolá původní metodu a profiltruje výsledek na .*Není jednodušší nechat tu původní metodu bejt a udělat si ten filtr bokem?
$fileFinder = new FileFinder(); $filter = new NoHiddenFilesFilter($fileFinder->getFiles()); $files = $filter->getFiltered();Nebo použít dekorátor
$baseFileFinder = new FileFinder(); $noHiddenFilesFinder = new NoHiddenFilesFinder($fileFinder); $files = $noHiddenFilesFinder->getFiles();V obou případech nemusíte na původní třídu ani hrábnout.
class aplikace -(1)-> class fileFinder -(2)-> class htmlRendererRozhodnu se, že chci upravit fileFinder diskutovaným způsobem. A mám následující možnosti: 1) aplikace musí být naprogramovaná tak, že umí nahradit třídu fileFinder jinou (např. v konfiguráku bude jméno třídy) 2) fileFinder musí mít rozhraní pro aplikování vybraných operací s možností ovlivnit výsledné chování - tedy fileFinder musí mít rozhraní pro pluginy a v runtime někde uloženou jejich konfiguraci - to je Vaše řešení? 3) do místa (1) vložím vlastní kód, který udělá co bude potřebovat, využije třeba alternativní třídu pro fileFinder, ale pak musí zajistit volání htmlRendereru v kroku (2) sám 4) řešení co sem navrhl odpoledne - tedy nějak elegantně zařídím, aby celá aplikace používala místo třídy fileFinder úplně jinou třídu (potomka původní nebo implementující stejný interface) Varianta 1) a 2) je OK, ale vyžaduje předem vyspecifikované podporované změny chování aplikace. Každé rozšíření těchto možností znamená netriviální úpravu aplikace. Navíc tato řešení neumí měnit předky používaných metod. Neumí se "vklínit" do posloupnosti dědění, a nahradit pouze jeden článek. Takto je možné pouze v libovolném místě řetěz dědění přetnout a pak znovu doimplementovat až do finálních tříd (tedy redundance kódu a druhotně podobný nešvar jako má 3) Varianta 3) se mi hrubě nelíbí. Vyžaduje dost redundantní práce. Co říkáte na Variantu 4)?
Pokud je tohle posloupnost volání, tak to je instance něčeho co pracovně nazývám architektura trubka nebo štafeta. Tam máte natvrdo zadrátovánou tu šipku č. 2 a nemůžete s tím nic udělat. To je váš hlavní problém, kterého se potřebujete zbavit. Pokud byste volání předělal takto:class aplikace -(1)-> class fileFinder -(2)-> class htmlRenderer
class aplikace -> class fileFinder <- $files -> class htmlRendererTak s tím můžete pak dělat co chcete.
varianta (A): nezávisle fungující Finder a Filter class aplikace -> class fileFinder <- $files -> class fileFilter <- $filteredFiles -> class htmlRenderernebo
varianta (B): Dědění nebo lépe Dekorátor class aplikace -> class filteredFileFinder -> class fileFinder <- $files <- $filteredFiles -> class htmlRenderer
Mým cílem je aplikace, která něco umí a je možné ji co nejširším způsobem a s co nejmenčí redundancí kódu upravovat.Můžete tohle aplikovat na stávající požadavky, nebo ty, které s nějakou rozumnou pravděpodobností očekáváte, ale nemůžete udělat univerzální stroj.
1) aplikace musí být naprogramovaná tak, že umí nahradit třídu fileFinder jinou (např. v konfiguráku bude jméno třídy)To je klasický příklad použití vzoru Factory.
varianta (C): Factory $className = getConfigOption("fileFinderClass"); $factory = new FileFinderFactory(); $fileFinder = $factory->createFileFinder($className);
2) fileFinder musí mít rozhraní pro aplikování vybraných operací s možností ovlivnit výsledné chování - tedy fileFinder musí mít rozhraní pro pluginy a v runtime někde uloženou jejich konfiguraci - to je Vaše řešení?To by byl následující kód:
varianta (D): Filter jako plugin funkcionalita Finderu $filter = new WhateverFilter(); $fileFinder = new FileFinder($filter); $files = $fileFinder->getFiles();To je ještě další varianta, kterou můžete použít.
3) do místa (1) vložím vlastní kód, který udělá co bude potřebovat, využije třeba alternativní třídu pro fileFinder, ale pak musí zajistit volání htmlRendereru v kroku (2) sámTo je něco čemu byste se měl vyhnout - fileFinder by měl výsledek vracet a ne štafetově předávat a mělo by mu být úplně jedno kdo ho zavolal a komu ten výsledek vrátí. Pak nebude problém s vložením kódu.
4) řešení co sem navrhl odpoledne - tedy nějak elegantně zařídím, aby celá aplikace používala místo třídy fileFinder úplně jinou třídu (potomka původní nebo implementující stejný interface)Tím pouze používáte pneumatické kladivo tam kde stačí trochu ťuknout hřebíček.
Neumí se "vklínit" do posloupnosti dědění, a nahradit pouze jeden článek.Proto se dědění moc nepoužívá - vytváří vazby moc natvrdo. Pokud tam potřebujete něco vklínit, je lepší použít volnější vazby, viz příklady. V kódu nahoře jsem označil varianty ABCD, chtěl bych shrnout výhody a nevýhody každé: A) (nezávislé třídy Finder a Filter) nejobecnější možnost, kde ani jedna třída neví o jiné - můžete kombinovat všechno se vším a udělat téměř jakékoliv chování. B) (Filter jako dekorátor nad Finderem) něco jako dědění, můžete před a po volání základního Finderu provést libovolnou modifikaci a vrátit výsledek ve stejném formátu. Oproti dědění můžete ty modifikace libovolně nabalovat na sebe a to i v době běhu aplikace. C) (Factory) výroba různých komponent (Finderů, Filtrů, ...) je schována na centrální místo, a případně konfigurovatelná uživatelem. Řekl bych, že to je spíš doplňková záležitost k ostatním variantám. D) (Plugin Filter) implicitně předpokládáte že se nějaký filtr použít musí, byť třeba prázdný. Hodí se, pokud je hodně jednoduchých Filtrů ale třeba jen jeden Finder. Místo jednoho filtru můžete třeba pluginovat pole filtrů atd.
...nejspíš tedy půjdu cestou "pneumatického kladiva"Akorát že, i když tu třídu nahradíte v runtime nebo nějakým hackem s include, tak nevyřešíte podstatu problému a to sice, že budete mít pořád na krku tu odpornou povinnost v náhradní třídě volat ten htmlRenderer.
C) souhlasím, dobrá věc, ale dělat tak všechny třídy v celé aplikaci je IMO nesmysl (a ani to nejde)Jsou na to frameworky.
Myslím, že ne... resp. šikovným designem metod docílím toho, že bude nějaká "worker" metoda, kterou můžu měnit a další metody zařídí začlenění do systému - těch se dotýkat nebudu (moct). Navíc je tak velice elegantně vyřešeno automatické používání nové funkčnosti v celém systému....nejspíš tedy půjdu cestou "pneumatického kladiva"Akorát že, i když tu třídu nahradíte v runtime nebo nějakým hackem s include, tak nevyřešíte podstatu problému a to sice, že budete mít pořád na krku tu odpornou povinnost v náhradní třídě volat ten htmlRenderer.
Jako např? ...jak řeší dědění z těchto tříd? Nechci už moc prudit, odkaz na doc úplně stačíC) souhlasím, dobrá věc, ale dělat tak všechny třídy v celé aplikaci je IMO nesmysl (a ani to nejde)Jsou na to frameworky.
šikovným designem metod docílím toho, že bude nějaká "worker" metoda, kterou můžu měnitSuper, to zní dobře.
Jako např? ...jak řeší dědění z těchto tříd? Nechci už moc prudit, odkaz na doc úplně stačíZkuste se podívat/inspirovat např. http://substrate-php.org/ případně existuje asi kopa alternativ... hledejte "php ioc framework". Dědění (implementace) bych doporučil na nějaký čas úplně vynechat a zkusit to řešit přes ten "šikovný design"...Díky!
Tiskni
Sdílej: